Data Import
Let’s import our data into R now so that we can explore the data further.
First let’s just get a general sense of our data. We can do that using the glimpse() function of the dplyr package (it is also in the tibble package).
Rows: 5,880
Columns: 11
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ location_name <chr> "Global", "Global", "Global", "Global", "Global", "Glo…
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116,…
$ rei_name <chr> "Diet low in fruits", "Diet low in fruits", "Diet low …
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All Avail…
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "Female", …
$ parameter <chr> "continuous", "continuous", "continuous", "continuous"…
$ mean <dbl> 8.703202e+01, 9.953182e+01, 1.975187e+02, 1.832338e+02…
$ upper <dbl> 8.988734e+01, 1.023450e+02, 2.083679e+02, 1.921103e+02…
$ lower <dbl> 8.452347e+01, 9.672140e+01, 1.887154e+02, 1.754019e+02…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/day", …
Rows: 88,200
Columns: 11
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ location_name <chr> "Global", "Global", "Global", "Global", "Global", "Glo…
$ rei_name <chr> "Diet low in fruits", "Diet low in fruits", "Diet low …
$ age_group_id <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 31, 32…
$ age_group_name <chr> "25 to 29", "30 to 34", "35 to 39", "40 to 44", "45 to…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male", "Male"…
$ parameter <chr> "continuous", "continuous", "continuous", "continuous"…
$ mean <dbl> 68.54567, 72.62209, 76.73157, 81.03910, 88.79202, 95.9…
$ upper <dbl> 75.16806, 80.00433, 84.73205, 89.52747, 100.94301, 107…
$ lower <dbl> 63.17081, 66.78018, 71.04691, 73.82734, 80.40971, 86.4…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/day", …
Here we can tell that the sep_age_diet_data is much larger than the diet_data. The diet_data has only 5,880 rows while the sep_age_diet_data has 88,200 rows!
However, both files appear to have the same column structure with 11 variables each.
The skim() function of the skimr package is also really helpful for getting a general sense of your data.
Data summary
| Name |
diet_data |
| Number of rows |
5880 |
| Number of columns |
11 |
| _______________________ |
|
| Column type frequency: |
|
| character |
6 |
| numeric |
5 |
| ________________________ |
|
| Group variables |
None |
Variable type: character
| location_name |
0 |
1 |
4 |
32 |
0 |
196 |
0 |
| rei_name |
0 |
1 |
16 |
39 |
0 |
15 |
0 |
| age_group_name |
0 |
1 |
18 |
18 |
0 |
1 |
0 |
| sex |
0 |
1 |
4 |
6 |
0 |
2 |
0 |
| parameter |
0 |
1 |
10 |
10 |
0 |
1 |
0 |
| unit |
0 |
1 |
5 |
11 |
0 |
2 |
0 |
Variable type: numeric
| year_id |
0 |
1 |
2017.00 |
0.00 |
2017 |
2017.00 |
2017.00 |
2017.00 |
2017.00 |
▁▁▇▁▁ |
| rei_id |
0 |
1 |
133.67 |
53.93 |
111 |
114.00 |
118.00 |
123.00 |
333.00 |
▇▁▁▁▁ |
| mean |
0 |
1 |
34.81 |
60.13 |
0 |
0.45 |
8.38 |
42.66 |
566.69 |
▇▁▁▁▁ |
| upper |
0 |
1 |
37.94 |
65.30 |
0 |
0.49 |
9.22 |
46.54 |
624.23 |
▇▁▁▁▁ |
| lower |
0 |
1 |
31.93 |
55.40 |
0 |
0.42 |
7.52 |
39.21 |
513.22 |
▇▁▁▁▁ |
Notice how there is a column providing the number of missing observations for each variable. It looks like our data is very complete and we do not have any missing data. We also get a sense about the size of our data.
The n_unqiue column shows us the number of unique values for each of our columns.
Let’s take a look at sep_age_diet_data.
Data summary
| Name |
sep_age_diet_data |
| Number of rows |
88200 |
| Number of columns |
11 |
| _______________________ |
|
| Column type frequency: |
|
| character |
6 |
| numeric |
5 |
| ________________________ |
|
| Group variables |
None |
Variable type: character
| location_name |
0 |
1 |
4 |
32 |
0 |
196 |
0 |
| rei_name |
0 |
1 |
16 |
39 |
0 |
15 |
0 |
| age_group_name |
0 |
1 |
7 |
8 |
0 |
15 |
0 |
| sex |
0 |
1 |
4 |
6 |
0 |
2 |
0 |
| parameter |
0 |
1 |
10 |
10 |
0 |
1 |
0 |
| unit |
0 |
1 |
5 |
11 |
0 |
2 |
0 |
Variable type: numeric
| year_id |
0 |
1 |
2017.00 |
0.00 |
2017 |
2017.00 |
2017.00 |
2017.00 |
2017.00 |
▁▁▇▁▁ |
| age_group_id |
0 |
1 |
32.87 |
54.46 |
10 |
13.00 |
17.00 |
30.00 |
235.00 |
▇▁▁▁▁ |
| mean |
0 |
1 |
39.84 |
63.86 |
0 |
0.56 |
10.80 |
52.63 |
604.01 |
▇▁▁▁▁ |
| upper |
0 |
1 |
48.07 |
78.38 |
0 |
0.70 |
13.55 |
59.96 |
806.98 |
▇▁▁▁▁ |
| lower |
0 |
1 |
33.46 |
54.54 |
0 |
0.42 |
8.46 |
44.87 |
639.06 |
▇▁▁▁▁ |
We can see that there are many more rows in this data set.
Let’s take a look at the different dietary risk factors considered. To do this we will use the distinct() function of the dplyr package.
This function grabs only the distinct or unique rows from a given variable (rei_name, in our case) of a given data frame (diet_data, in our case).
# A tibble: 15 x 1
rei_name
<chr>
1 Diet low in fruits
2 Diet low in vegetables
3 Diet low in whole grains
4 Diet low in nuts and seeds
5 Diet low in milk
6 Diet high in red meat
7 Diet high in processed meat
8 Diet high in sugar-sweetened beverages
9 Diet low in fiber
10 Diet low in seafood omega-3 fatty acids
11 Diet low in polyunsaturated fatty acids
12 Diet high in trans fatty acids
13 Diet high in sodium
14 Diet low in calcium
15 Diet low in legumes
We will be using the %>% pipe for sequential steps in our code later on. This will make more sense when we have multiple sequential steps using the same data object.
We could do the same code as above using this notation. For example we first grab the diet_data, then we select the distinct values of the rei_name variable.
# A tibble: 15 x 1
rei_name
<chr>
1 Diet low in fruits
2 Diet low in vegetables
3 Diet low in whole grains
4 Diet low in nuts and seeds
5 Diet low in milk
6 Diet high in red meat
7 Diet high in processed meat
8 Diet high in sugar-sweetened beverages
9 Diet low in fiber
10 Diet low in seafood omega-3 fatty acids
11 Diet low in polyunsaturated fatty acids
12 Diet high in trans fatty acids
13 Diet high in sodium
14 Diet low in calcium
15 Diet low in legumes
OK, so that gives us an idea of what dietary factors we can explore, and we can see that there are 15 of them.
Let’s see if the location_name values are the same between both CSV files. To do this we will use the setequal() function of dplyr.
[1] TRUE
OK, we got the value of TRUE, so it looks like the same locations are in both files.
Note: In this case were comparing two different objects so using the pipe is not as useful.
Let’s take a look at the locations included in the data.
OK, so there are global values, as well as values for 195 countries.
Let’s take a look at the data when we order it by the mean consumption rate column. We can do so using the arrange() function of the dplyr package.
Rows: 5,880
Columns: 11
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ location_name <chr> "Lebanon", "Lebanon", "Italy", "Turkey", "Kazakhstan",…
$ rei_id <dbl> 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,…
$ rei_name <chr> "Diet high in trans fatty acids", "Diet high in trans …
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All Avail…
$ sex <chr> "Male", "Female", "Male", "Male", "Male", "Male", "Mal…
$ parameter <chr> "continuous", "continuous", "continuous", "continuous"…
$ mean <dbl> 0.000727793, 0.000819837, 0.001357473, 0.001411079, 0.…
$ upper <dbl> 0.000892791, 0.001007998, 0.001491509, 0.001727481, 0.…
$ lower <dbl> 0.000585340, 0.000670438, 0.001233583, 0.001134972, 0.…
$ unit <chr> "%energy/day", "%energy/day", "%energy/day", "%energy/…
OK, so it looks like people in Lebanon don’t eat very many trans fatty acids.
Let’s also figure out how many values there are in each age group of the data that is separated by age. We will use the count() function of the dplyr package to do this.
# A tibble: 15 x 2
age_group_name n
<chr> <int>
1 25 to 29 5880
2 30 to 34 5880
3 35 to 39 5880
4 40 to 44 5880
5 45 to 49 5880
6 50 to 54 5880
7 55 to 59 5880
8 60 to 64 5880
9 65 to 69 5880
10 70 to 74 5880
11 75 to 79 5880
12 80 to 84 5880
13 85 to 89 5880
14 90 to 94 5880
15 95 plus 5880
That’s a lot of values!
Let’s look a bit deeper to try to understand why. We can use the count() function again but get the number of values for each category within sex, age_group_name and location_name of the data.
# A tibble: 5,880 x 4
sex age_group_name location_name n
<chr> <chr> <chr> <int>
1 Female 25 to 29 Afghanistan 15
2 Female 25 to 29 Albania 15
3 Female 25 to 29 Algeria 15
4 Female 25 to 29 American Samoa 15
5 Female 25 to 29 Andorra 15
6 Female 25 to 29 Angola 15
7 Female 25 to 29 Antigua and Barbuda 15
8 Female 25 to 29 Argentina 15
9 Female 25 to 29 Armenia 15
10 Female 25 to 29 Australia 15
# … with 5,870 more rows
OK, so it looks like these are probably the consumption values for each of the different dietary factors (since there were 15 different factors) for each age group and gender combination within each country.
We can confirm this by filtering the data to one of the age groups, for a single gender, and for a single location. To do this we can use the filter() function of the dplyr package. Notice that we need to use two equal signs == to specify what values we would like for each variable.
# A tibble: 15 x 11
year_id location_name rei_name age_group_id age_group_name sex parameter
<dbl> <chr> <chr> <dbl> <chr> <chr> <chr>
1 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
2 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
3 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
4 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
5 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
6 2017 Afghanistan Diet hi… 10 25 to 29 Fema… continuo…
7 2017 Afghanistan Diet hi… 10 25 to 29 Fema… continuo…
8 2017 Afghanistan Diet hi… 10 25 to 29 Fema… continuo…
9 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
10 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
11 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
12 2017 Afghanistan Diet hi… 10 25 to 29 Fema… continuo…
13 2017 Afghanistan Diet hi… 10 25 to 29 Fema… continuo…
14 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
15 2017 Afghanistan Diet lo… 10 25 to 29 Fema… continuo…
# … with 4 more variables: mean <dbl>, upper <dbl>, lower <dbl>, unit <chr>
This confirms that for each of the 15 dietary factors, our unit of observation is a combination of gender, age and country. However, before we proceed with our analysis, we will want to perform some additional data wrangling. To do this, we will introduce the pdftools package, which will allow us to pull additional data from the manuscript itself.
Data Wrangling
While all of the mean consumption values are reported in grams, each dietary factor has a different amount that is considered optimal for consuming. To make the consumption values more comparable across factors, let’s also get some data from the PDF of the paper so that we can calculate consumption of these dietary factors as percentages of the daily optimum.
We are interested in this table on page 3:

First let’s import the PDF using the pfd_text() function of the pdftools package.
We can use the base summary() function to get a sense of what the data looks like. By base we mean that these functions are part of the base package and are loaded automatically on startup of R. Thus library(base) is not required.
Length Class Mode
15 character character
We can see that we have 15 different character strings. Each one contains the text on each of the 15 different pages of the PDF.
Again, the table we are interested in is on the third page, so let’s grab just that portion of the PDF. The top of this page looks like:

Length Class Mode
1 character character
chr " Articles\nin systolic blood pressure, and then estimated the Disease-specific deaths and disability-adjusted\nrelationship between change in systolic blood pressure life-years\nand disease outcomes.14 Data on disease-specific deaths and disability-adjusted\n life-years (DALYs) by age, sex, country, and year were\nOptimal level of intake "| __truncated__
Here we can see that the pdf_table object now contains the text from the 3rd page as a single large character string. However the text is difficult to read because of the column structure in the PDF. Now let’s try to grab just the text in the table.
One way to approach this is to split the string by some pattern that we notice in the table.

All the rows of interest of the table appear to start with the word "Diet". Moreover, only the capitalized form of the word "Diet" appears to be within the table, and it is not present in the preceding text (although "diet" is).

Let’s use the str_split() function of the stringr package to split the data within the object called pdf_table by the word "Diet". Only lines from page 3 that contain the word "Diet" will be selected (and not "diet" as this function is case-sensitive). Each section of the text that contains "Diet" will be split into individual pieces every time the word "Diet" occurs and the word itself will be removed.
In this case we are also using the magrittr assignment pipe or double pipe that looks like this %<>% of the magrittr package. This allows us use the pdf_table data as input to the later steps but also reassign the output to the same data object name.
Using the base::summary() and dplyr::glimpse() function we can see that we created a list of the rows in the table that contained the word "Diet". We can see that we start with the row that contains "low in fruits".
Length Class Mode
[1,] 17 -none- character
List of 1
$ : chr [1:17] " "| __truncated__ " low in fruits Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruit"| __truncated__ " low in vegetables Mean daily consumption of vegetables (fresh, frozen, cooked, canned, or dried v"| __truncated__ " low in legumes Mean daily consumption of legumes (fresh, frozen, cooked, canned, or dried legu"| __truncated__ ...
In order to extract the values that we want from these character strings, we will use some additional functions from the stringr package. RStudio creates really helpful cheat sheets like this one which shows you all the major functions in the stringr package. You can download others here.

You can see that we could have also used the str_split_fixed() function which would also separate the substrings into different columns of a matrix, however we would need to know the number of substrings or pieces that we would like returned.
For more information about str_split() see here.
Let’s separate the values within the list using the base unlist function, this will allow us to easily select the different substrings within the object called pdf_table.
It’s important to realize that the first split will split the text before the first occurrence of "Diet" as the first value in the output. (This is why there are 17 elements in pdf_table rather than 15, the number of rows in the table.) We could use the first() function of the dplyr package to look at this value. However, we will suppress the output as this is quite large.
Instead we can take a look at the second element of the list. using the nth() function of dplyr.
[1] " low in fruits Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruits, excluding 250 g (200–300) per day 94·9\n fruit juices and salted or pickled fruits)\n "
Indeed this looks like the first row of interest in our table:

Using the last() and the nth() functions of the dplyr package we can take a look at the last values of the list.
[1] " high in sodium 24 h urinary sodium measured in g per day 3 g (1–5) per day* 26·2\n *To reflect the uncertainty in existing evidence on optimal level of intake for sodium, 1–5 g per day was considered as the uncertainty range for the optimal level of sodium where less than 2·3 g per day is the\n intake level of sodium associated with the lowest level of blood pressure in randomised controlled trials and 4–5 g per day is the level of sodium intake associated with the lowest risk of cardiovascular disease in\n observational studies.\n Table: "
[1] "ary risk factor exposure definitions, optimal level, and data representativeness index, 1990–2017\nwww.thelancet.com Published online April 3, 2019 http://dx.doi.org/10.1016/S0140-6736(19)30041-8 3\n"

We don’t need this part of the table or the text before the table if we just want the consumption recommendations.
So we will select the second through the second-to-last of the substrings. Since we have seventeen substrings, we will select the second through the sixteenth. However a better way to do this rather than selecting by index, would be to select phrases that are unique to the text within the table that we want. We will use the str_subset() function of stringr package to select the table rows with consumption guidelines. Most of the rows have the phrase “Mean daily consumption”, however, there are other phrases for some of the rows, including “Mean daily intake” and “24 h sodium”. So we will subset for each of these phrases.
Notice that we separate the different patterns to look for using vertical bar character "|" and that all of the patterns are within quotation marks together.
Question opportunity:
What other string patterns could you use to subset the rows of the table that we want?
Why might it be better to subset based on the text rather than the index?
Now the first row is what we want:
[1] " low in fruits Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruits, excluding 250 g (200–300) per day 94·9\n fruit juices and salted or pickled fruits)\n "
And the last row is what we want:
[1] " high in sodium 24 h urinary sodium measured in g per day 3 g (1–5) per day* 26·2\n *To reflect the uncertainty in existing evidence on optimal level of intake for sodium, 1–5 g per day was considered as the uncertainty range for the optimal level of sodium where less than 2·3 g per day is the\n intake level of sodium associated with the lowest level of blood pressure in randomised controlled trials and 4–5 g per day is the level of sodium intake associated with the lowest risk of cardiovascular disease in\n observational studies.\n Table: "
At this point, we have a better look at the current representation of the table data in R, and we might notice something that will need to be fixed. In the string above, the decimal points from the PDF are being recognized as something called an interpunct instead of a period or decimal. An interpunct is a centered dot, as opposed to a period or decimal that is aligned to the bottom of the line.
The interpunct was previously used to separate words in certain languages, like ancient Latin.
You can produce an interpunct on a Mac like this:
It is important to replace these for later when we want these values to be converted from character strings to numeric. We will again use the stringr package. This time we will use the str_replace_all() function which replaces all instances of a pattern in an individual string. In this case we want to replace all instances of the interpunct with a decimal point.
Looks good!
[1] " high in sodium 24 h urinary sodium measured in g per day 3 g (1–5) per day* 26.2\n *To reflect the uncertainty in existing evidence on optimal level of intake for sodium, 1–5 g per day was considered as the uncertainty range for the optimal level of sodium where less than 2.3 g per day is the\n intake level of sodium associated with the lowest level of blood pressure in randomised controlled trials and 4–5 g per day is the level of sodium intake associated with the lowest risk of cardiovascular disease in\n observational studies.\n Table: "
Now we will try to split the strings for each row based on the presence of two spaces to create the columns of the table, as there appears to be more than one space between the columns. The resulting substrings will be separated by quotes.
For additional details, the second page of the stringr cheat sheet has more information about using “Special Characters” in stringr. For example \\s is interpreted as a space as the \\ indicates that the s should be interpreted as a special character and not simply the letter s. The {2,} indicates two or more spaces, while {2} would indicate exactly two spaces.

List of 15
$ : chr [1:6] " low in fruits" "Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruits, excluding" "250 g (200–300) per day" "94.9" ...
$ : chr [1:7] " low in vegetables" "Mean daily consumption of vegetables (fresh, frozen, cooked, canned, or dried vegetables," "360 g (290–430) per day" "94.9" ...
$ : chr [1:5] " low in legumes" "Mean daily consumption of legumes (fresh, frozen, cooked, canned, or dried legumes)" "60 g (50–70) per day" "94.9" ...
$ : chr [1:7] " low in whole grains" "Mean daily consumption of whole grains (bran, germ, and endosperm in their natural" "125 g (100–150) per day" "94.9" ...
$ : chr [1:5] " low in nuts and seeds" "Mean daily consumption of nut and seed foods" "21 g (16–25) per day" "94.9" ...
$ : chr [1:6] " low in milk" "Mean daily consumption of milk including non-fat, low-fat, and full-fat milk, excluding soy" "435 g (350–520) per day" "94.9" ...
$ : chr [1:6] " high in red meat" "Mean daily consumption of red meat (beef, pork, lamb, and goat, but excluding poultry, fish," "23 g (18–27) per day" "94.9" ...
$ : chr [1:6] " high in processed meat" "Mean daily consumption of meat preserved by smoking, curing, salting, or addition of" "2 g (0–4) per day" "36.9" ...
$ : chr [1:6] " high in sugar-sweetened Mean daily consumption of beverages with ≥50 kcal per 226.8 serving, including carbonated" "3 g (0–5) per day" "36.9" "beverages" ...
$ : chr [1:6] " low in fibre" "Mean daily intake of fibre from all sources including fruits, vegetables, grains, legumes, and" "24 g (19–28) per day" "94.9" ...
$ : chr [1:5] " low in calcium" "Mean daily intake of calcium from all sources, including milk, yogurt, and cheese" "1.25 g (1.00–1.50) per day" "94.9" ...
$ : chr [1:5] " low in seafood omega-3 Mean daily intake of eicosapentaenoic acid and docosahexaenoic acid" "250 mg (200–300) per day" "94.9" "fatty acids" ...
$ : chr [1:7] " low in polyunsaturated" "Mean daily intake of omega-6 fatty acids from all sources, mainly liquid vegetable oils," "11% (9–13) of total daily energy" "94.9" ...
$ : chr [1:6] " high in trans fatty acids" "Mean daily intake of trans fat from all sources, mainly partially hydrogenated vegetable oils" "0.5% (0.0–1.0) of total daily energy" "36.9" ...
$ : chr [1:8] " high in sodium" "24 h urinary sodium measured in g per day" "3 g (1–5) per day*" "26.2" ...
Now we can see that each of our 15 strings has been split into pieces, but unfortunately, it was not completely consistent across dietary factors. Why did this happen? If we look closely, we can see that the sugar-sweetened beverage and the seafood category had only one space between the first and second columns. These are the columns about the dietary category and the one that describes in more detail what the consumption suggestion is about.
The values for these two columns appear to be together still in the same substring for these two categories. We can see this because there are no quotation marks adjacent to the word "Mean".
Here you can see how the next substring should have started with the word "Mean" by the new inclusion of a quotation mark ". The red rectangles indicate the problematic substrings, while the green rectangles show examples where the split worked correctly.

We can add an extra space in front of the word "Mean" for these particular categories and then try splitting again.
Since we originally split based on two or more spaces, we can just add a space in front of the word “Mean” for all the pdf_table strings and then try subsetting again. We can use the str_which() function of the stringr package to find the index of these particular cases.
[1] 9 12
Here we can use this function with [] to see just the strings that match these patterns within pdf_table:
[1] " high in sugar-sweetened Mean daily consumption of beverages with ≥50 kcal per 226.8 serving, including carbonated 3 g (0–5) per day 36.9\n beverages beverages, sodas, energy drinks, fruit drinks, but excluding 100% fruit and vegetable juices\n "
[2] " low in seafood omega-3 Mean daily intake of eicosapentaenoic acid and docosahexaenoic acid 250 mg (200–300) per day 94.9\n fatty acids\n "
Now we can replace these values within the pdf_table object after adding a space in front of “Mean”:
And now we can try splitting again by two or more spaces:
We could also just add a space in front of all the values of “Mean” in pdf_table since the split was performed based on two or more spaces. Thus the other elements in pdf_table would also be split just as before despite the additional space.
Looks better!
We want just the first (the food category) and third column (the optimal consumption amount suggested) for each row in the table. However, the table is current stored as a list of character vectors, so it is not quite so simple to extract these values.
We can use the map function of the purrr package to accomplish this.
The map function allows us to perform the same action multiple times across each element within an object, in this case, a list.
The following will allow us to select the first or third substring from each element of the pdf_table object.
[[1]]
[1] " low in fruits"
[[2]]
[1] " low in vegetables"
[[3]]
[1] " low in legumes"
[[4]]
[1] " low in whole grains"
[[5]]
[1] " low in nuts and seeds"
[[6]]
[1] " low in milk"
[[1]]
[1] "250 g (200–300) per day"
[[2]]
[1] "360 g (290–430) per day"
[[3]]
[1] "60 g (50–70) per day"
[[4]]
[1] "125 g (100–150) per day"
[[5]]
[1] "21 g (16–25) per day"
[[6]]
[1] "435 g (350–520) per day"
Now we will create a tibble using this data. However, currently both category and amount are of class list. To create a tibble we need to unlist the data to create vectors.
[1] "list"
[1] "character"
We could have done all of this at once in one command like this:
Now we will create a tibble, which is an important data frame structure in the tidyverse which allows us to use other packages in the tidyverse with our data.
We will name our tibble columns now as we create our tibble using the tibble() function of both the tidyr and the tibble packages, as names are required in tibbles.
# A tibble: 15 x 2
category amount
<chr> <chr>
1 " low in fruits" 250 g (200–300) per day
2 " low in vegetables" 360 g (290–430) per day
3 " low in legumes" 60 g (50–70) per day
4 " low in whole grains" 125 g (100–150) per day
5 " low in nuts and seeds" 21 g (16–25) per day
6 " low in milk" 435 g (350–520) per day
7 " high in red meat" 23 g (18–27) per day
8 " high in processed meat" 2 g (0–4) per day
9 " high in sugar-sweetened" 3 g (0–5) per day
10 " low in fibre" 24 g (19–28) per day
11 " low in calcium" 1.25 g (1.00–1.50) per day
12 " low in seafood omega-3" 250 mg (200–300) per day
13 " low in polyunsaturated" 11% (9–13) of total daily energy
14 " high in trans fatty acids" 0.5% (0.0–1.0) of total daily energy
15 " high in sodium" 3 g (1–5) per day*
Looking pretty good!
Separating values within a variable
Recall that the main goal of this data wrangling is to extract the optimal intake level for each dietary factor. So while we have managed to pull and organize the data from the pdf table, we need to further process the results to isolate this numeric value.
Do to this, we want to separate the different numbers within the amount column, to isolate the optimal amount, and the optimal range, and eventually convert them to numeric values.
Recall what the original table looked like: 
We can use the tidyr::separate() function to separate the data within the amount column into three new columns based on the optimal level and the optimal range. We can separate the values based on the open parentheses "(" and the long dash "–" characters. Again we will use the bar "|" to indicate that we want to separate by either character.
# A tibble: 15 x 4
category optimal lower upper
<chr> <chr> <chr> <chr>
1 " low in fruits" "250 g " 200 300) per day
2 " low in vegetables" "360 g " 290 430) per day
3 " low in legumes" "60 g " 50 70) per day
4 " low in whole grains" "125 g " 100 150) per day
5 " low in nuts and seeds" "21 g " 16 25) per day
6 " low in milk" "435 g " 350 520) per day
7 " high in red meat" "23 g " 18 27) per day
8 " high in processed meat" "2 g " 0 4) per day
9 " high in sugar-sweetened" "3 g " 0 5) per day
10 " low in fibre" "24 g " 19 28) per day
11 " low in calcium" "1.25 g " 1.00 1.50) per day
12 " low in seafood omega-3" "250 mg " 200 300) per day
13 " low in polyunsaturated" "11% " 9 13) of total daily energy
14 " high in trans fatty acids" "0.5% " 0.0 1.0) of total daily energy
15 " high in sodium" "3 g " 1 5) per day*
Let’s also create a new variable/column in our tibble that indicates the direction of over- or under-consumption that can be harmful for each dietary factor.
# A tibble: 15 x 5
direction food optimal lower upper
<chr> <chr> <chr> <chr> <chr>
1 " low" fruits "250 g " 200 300) per day
2 " low" vegetables "360 g " 290 430) per day
3 " low" legumes "60 g " 50 70) per day
4 " low" whole grains "125 g " 100 150) per day
5 " low" nuts and seeds "21 g " 16 25) per day
6 " low" milk "435 g " 350 520) per day
7 " high" red meat "23 g " 18 27) per day
8 " high" processed meat "2 g " 0 4) per day
9 " high" sugar-sweetened "3 g " 0 5) per day
10 " low" fibre "24 g " 19 28) per day
11 " low" calcium "1.25 g " 1.00 1.50) per day
12 " low" seafood omega-3 "250 mg " 200 300) per day
13 " low" polyunsaturated "11% " 9 13) of total daily energy
14 " high" trans fatty acids "0.5% " 0.0 1.0) of total daily energy
15 " high" sodium "3 g " 1 5) per day*
If we wanted to remove the direction variable we could use the modify_at() function of the purrr package:
Data cleaning with regular expressions
OK, looking better, but we still need a bit of cleaning to remove symbols and extra words from the columns. Some of the extra symbols include: "%", ")" and the "*".
The "*" and the ")" are what we call metacharacters or regular expressions. These are characters that have special meanings.

Now we need the "\\" to indicate that we want these characters to be matched exactly and not interpreted as the meaning of the symbol. Previously we used [] around the characters when we separated the optimal amount columns. Recall that we used "[(|–]". This worked because these are punctuation characters, we could have also used "\\(|–".
See here for more info about regular expressions in R.
Click here for a simple example of regular expressions using the str_count() function of the stringr package
The str_count() function counts the number of instances of a character string. In this case we will look for individual characters but you could also search for words or phrases.
[1] "Testing for ts or\ttabs can be tricky.(yes, it really can!*)\n"
Count the letter t:
[1] 5
Count tabs:
[1] 1
[1] 5
Count parentheses:
[1] 1
[1] 1
Count the occurrence of the asterix:
[1] 1
[1] 1
We also want to make a unit variable so that we can make sure that our units are consistent later.
[1] "250 g " "360 g " "60 g " "125 g " "21 g " "435 g " "23 g "
[8] "2 g " "3 g " "24 g " "1.25 g " "250 mg " "11% " "0.5% "
[15] "3 g "
Notice that the values that are percentages don’t have spaces between the number and the unit. We can separate the "optimal" values by a space or a percent symbol "%" using "|" to indicate that we want to separate by either. In this case we will lose the “%” and will need to add it back to those values.
# A tibble: 15 x 6
direction food lower optimal unit upper
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" fruits 200 250 "g" 300) per day
2 " low" vegetables 290 360 "g" 430) per day
3 " low" legumes 50 60 "g" 70) per day
4 " low" whole grains 100 125 "g" 150) per day
5 " low" nuts and seeds 16 21 "g" 25) per day
6 " low" milk 350 435 "g" 520) per day
7 " high" red meat 18 23 "g" 27) per day
8 " high" processed meat 0 2 "g" 4) per day
9 " high" sugar-sweetened 0 3 "g" 5) per day
10 " low" fibre 19 24 "g" 28) per day
11 " low" calcium 1.00 1.25 "g" 1.50) per day
12 " low" seafood omega-3 200 250 "mg" 300) per day
13 " low" polyunsaturated 9 11 "" 13) of total daily energy
14 " high" trans fatty acids 0.0 0.5 "" 1.0) of total daily energy
15 " high" sodium 1 3 "g" 5) per day*
Great, so to now we will add “%” to the unit variable for the "low in polyunsaturated" and "high in trans fatty acids" rows.
First we need to replace the empty values with NA using the na_if() function of the dplyr package.
# A tibble: 15 x 6
direction food lower optimal unit upper
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" fruits 200 250 g 300) per day
2 " low" vegetables 290 360 g 430) per day
3 " low" legumes 50 60 g 70) per day
4 " low" whole grains 100 125 g 150) per day
5 " low" nuts and seeds 16 21 g 25) per day
6 " low" milk 350 435 g 520) per day
7 " high" red meat 18 23 g 27) per day
8 " high" processed meat 0 2 g 4) per day
9 " high" sugar-sweetened 0 3 g 5) per day
10 " low" fibre 19 24 g 28) per day
11 " low" calcium 1.00 1.25 g 1.50) per day
12 " low" seafood omega-3 200 250 mg 300) per day
13 " low" polyunsaturated 9 11 <NA> 13) of total daily energy
14 " high" trans fatty acids 0.0 0.5 <NA> 1.0) of total daily energy
15 " high" sodium 1 3 g 5) per day*
Then to replace the NA values, we can use the replace_na() function in the tidyr package and the mutate() function of dplyr to specify which values to replace, in this case the NA values within the variable unit. Essentially this variable gets reassigned with the new values, as we mostly think of the mutate() function as creating new variables.
# A tibble: 2 x 6
direction food lower optimal unit upper
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" polyunsaturated 9 11 % 13) of total daily energy
2 " high" trans fatty acids 0.0 0.5 % 1.0) of total daily energy
Let’s also move unit to be the last column. We can use the select() and everything() functions of the dplyr package to do this.
Here you can see Hadley Wickham’s (Chief Scientist at RStudio) explanation for this behavior of select():
https://github.com/tidyverse/dplyr/issues/2838#issuecomment-306062800
To remove all of the remaining extra characters and words we will again use the stringr package. This time we will use the str_remove_all() function to remove all instances of these characters.
Nice! that’s pretty clean but we can do a bit more.
Data type conversion
One of the next things to notice about our data is all of our variables are of class character, which is not how we want them to be.
For example, the optimal amounts of consumption are currently of class character, which is indicated by the <chr> just below the column names/variable names of the guidelines tibble:
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1.00 1.25 1.50 g
12 " low" seafood omega-3 200 250 300 mg
13 " low" polyunsaturated 9 11 13 %
14 " high" trans fatty acids 0.0 0.5 1.0 %
15 " high" sodium 1 3 5 g
To convert these values to numeric we can use the mutate_at() function of the dplyr package.
The mutate_at() function allows us to perform a function on specific columns/variables within a tibble. We need to indicate which variables we would like to convert using vars(). In this case if we look at the beginning of the guidelines tibble, we can see that optimal, lower and upper should be converted. As these three columns are sequential, we can simply put a : between optimal and upper to indicate that we want all the variables in between these columns to be converted.
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1 1.25 1.5 g
12 " low" seafood omega-3 200 250 300 mg
13 " low" polyunsaturated 9 11 13 %
14 " high" trans fatty acids 0 0.5 1 %
15 " high" sodium 1 3 5 g
Great! Now these variables are of class <dbl> (stands for double) which indicates that they are numeric. Here is a link for more information on numeric classes in R.
If we had not replaced the "·" interpunct values to a period, conversion from character to numeric would be problematic and would result in NA values.
Data value reassignments
We seem to have lost the word "beverages" from the "sugar-sweetened beverages" category, as well as "fatty acids" from the "seafood omega 3 fatty acids", and the "polyunsaturated fatty acids" categories as the full category name was listed on two lines within the table. We would like to replace these values with the full name.
To select the food variable we will show you several options. Only a couple will work well with reassigning the data in that particular variable within guidelines without assigning an intermediate data object. We will look using mutate_at(), pull(), select(), and two styles of brackets ["variable name"] and [["variablename"]].
The bracket ["variable name"] option and the select() option will grab a tibble (data frame) version of the food column out of guidelines. However we can’t start commands with select for assignments.
# A tibble: 15 x 1
food
<chr>
1 fruits
2 vegetables
3 legumes
4 whole grains
5 nuts and seeds
6 milk
7 red meat
8 processed meat
9 sugar-sweetened
10 fibre
11 calcium
12 seafood omega-3
13 polyunsaturated
14 trans fatty acids
15 sodium
# A tibble: 15 x 1
food
<chr>
1 fruits
2 vegetables
3 legumes
4 whole grains
5 nuts and seeds
6 milk
7 red meat
8 processed meat
9 sugar-sweetened
10 fibre
11 calcium
12 seafood omega-3
13 polyunsaturated
14 trans fatty acids
15 sodium
pull() and the bracket [["variable name"]] option in contrast, will grab the vector version of the food data:
[1] "fruits" "vegetables" "legumes"
[4] "whole grains" "nuts and seeds" "milk"
[7] "red meat" "processed meat" "sugar-sweetened"
[10] "fibre" "calcium" "seafood omega-3"
[13] "polyunsaturated" "trans fatty acids" "sodium"
[1] "fruits" "vegetables" "legumes"
[4] "whole grains" "nuts and seeds" "milk"
[7] "red meat" "processed meat" "sugar-sweetened"
[10] "fibre" "calcium" "seafood omega-3"
[13] "polyunsaturated" "trans fatty acids" "sodium"
The pull() function can be very useful when combined with other functions (for example you typically want to use a vector with the str_replace() function), but just like select, we can’t start assignments with pull().
This is not possible and will result in an error:
This will only print the result, but not reassign the food variable values:
[1] "fruits" "vegetables"
[3] "legumes" "whole grains"
[5] "nuts and seeds" "milk"
[7] "red meat" "processed meat"
[9] "sugar-sweetened beverages" "fibre"
[11] "calcium" "seafood omega-3"
[13] "polyunsaturated" "trans fatty acids"
[15] "sodium"
Using select() would work as well to print the result (although the result structure is different):
[1] "c(\"fruits\", \"vegetables\", \"legumes\", \"whole grains\", \"nuts and seeds\", \"milk\", \"red meat\", \"processed meat\", \"sugar-sweetened beverages\", \"fibre\", \"calcium\", \"seafood omega-3\", \"polyunsaturated\", \"trans fatty acids\", \"sodium\")"
Question opportunity:
Why do these commands not reassign the food variable values?
The bracket option is great alternative and allows us to reassign the values within guidelines easily. Either of the two styles of brackets: ["variable name"] and [["variablename"]] will work.
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened beverages 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1 1.25 1.5 g
12 " low" seafood omega-3 fatty acids 200 250 300 mg
13 " low" polyunsaturated 9 11 13 %
14 " high" trans fatty acids 0 0.5 1 %
15 " high" sodium 1 3 5 g
Finally, the best option is probably the mutate_at() function from dplyr. In this case we need to include ~ in front of the function that we would like to use on the values in our food variables. We also include . as a replacement to reference the data that we want to use within str_replace() (which in this case is the food variable values of guidelines).
Notice we didn’t need this when we previously use mutate_at() with the as.numeric() function. This is because the str_replace() function requires us to specify what data we are using as one of the arguments, while as.numeric() does not.
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened beverages 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1 1.25 1.5 g
12 " low" seafood omega-3 fatty acids 200 250 300 mg
13 " low" polyunsaturated fatty acids 9 11 13 %
14 " high" trans fatty acids 0 0.5 1 %
15 " high" sodium 1 3 5 g
This might be considered a better option because it is more readable as to where the food data came from that we are replacing values within.
There is one last minor detail… the direction variable has leading spaces still. We can use str_trim() to fix that!
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fruits 200 250 300 g
2 low vegetables 290 360 430 g
3 low legumes 50 60 70 g
4 low whole grains 100 125 150 g
5 low nuts and seeds 16 21 25 g
6 low milk 350 435 520 g
7 high red meat 18 23 27 g
8 high processed meat 0 2 4 g
9 high sugar-sweetened beverages 0 3 5 g
10 low fibre 19 24 28 g
11 low calcium 1 1.25 1.5 g
12 low seafood omega-3 fatty acids 200 250 300 mg
13 low polyunsaturated fatty acids 9 11 13 %
14 high trans fatty acids 0 0.5 1 %
15 high sodium 1 3 5 g
OK! Now we know how much of each dietary factor we generally need for optimal health according to the guidelines used in this article.
Comparing data
Recall that the main goal of pulling the guideline amounts from the pdf was that we would like to see how the mean consumption rates for the different groups of people compared to the optimal intake guidelines.
One way we could do this is to calculate a consumption percentage of the optimal value.
To calculate this it would be helpful to put the guideline amounts with the average consumption rates into the same tibble, especially because the observed consumption data (diet_data and sep_age_diet_data) are very different dimensions from the guidelines data.
In order to create a tibble with our observed consumption rates with the suggested consumption rates, we will join our data using dplyr. In order to do so it is important that our different data sets have at least one column with the same values that we can use to join them together. So let’s first assess if that is the case.
# A tibble: 15 x 1
rei_name
<chr>
1 Diet low in fruits
2 Diet low in vegetables
3 Diet low in whole grains
4 Diet low in nuts and seeds
5 Diet low in milk
6 Diet high in red meat
7 Diet high in processed meat
8 Diet high in sugar-sweetened beverages
9 Diet low in fiber
10 Diet low in seafood omega-3 fatty acids
11 Diet low in polyunsaturated fatty acids
12 Diet high in trans fatty acids
13 Diet high in sodium
14 Diet low in calcium
15 Diet low in legumes
# A tibble: 15 x 1
food
<chr>
1 fruits
2 vegetables
3 legumes
4 whole grains
5 nuts and seeds
6 milk
7 red meat
8 processed meat
9 sugar-sweetened beverages
10 fibre
11 calcium
12 seafood omega-3 fatty acids
13 polyunsaturated fatty acids
14 trans fatty acids
15 sodium
We are actually pretty close: there are 15 dietary factors in each data set, and the names are nearly the same. To make them match completely, we can see that we need to remove the "Diet low in" and "Diet high in" phrases from the observed consumption data.
Also let’s double check that the two observed files have the same exact values for dietary factor names.
We can use the setequal() function from dplyr to check that the unique values for rei_name are the same for both diet_data and sep_age_diet_data.
[1] TRUE
Great!
Note that the default of the set_equal function ignores the order of values in rows. So we still don’t know if the order is the same.
We can check using the all_equal function of dplyr which reports back clues about what might be different if anything. Importantly we are including ignore_row_order = FALSE as the default is TRUE.
[1] TRUE
Looks like they are also in the same order.
Note that if any of the values are different, all_equal() will first report this and will not report that the rows are in a different order.
Click here to see a toy example about how the three comparison functions (setequal(), all_equal() (also all.equal() for tbl_df), and setdiff()) work in dplyr.
It’s important to realize that row order is ignored by bothsetequal() and setdiff().
Now let’s compare two tibbles that have different row orders and different values.
Here are our tibbles to compare:
# A tibble: 4 x 1
test
<chr>
1 A
2 B
3 AC
4 D
# A tibble: 4 x 1
test
<chr>
1 A
2 D
3 A
4 B
[1] "tbl_df" "tbl" "data.frame"
Since we are using tibbles, which are of class tbl_df we can use either all_equal or all.equal(). Notice that it doesn’t report rows being a different order because it first tells what rows have unique values or rows with a value that has a different number of frequency.
[1] "- Rows in x but not in y: 3\n"
[1] "- Rows in x but not in y: 3\n"
[1] "Component \"test\": 3 string mismatches"
[1] "Component \"test\": 3 string mismatches"
setequal() does not provide clues about what is different but TRUE (no differences) or FALSE (indicating at least one difference).
[1] FALSE
setdiff() tells us what is different and is dependent on the order of the objects compared, but prioritizes the values that are unique to each.
# A tibble: 1 x 1
test
<chr>
1 AC
# A tibble: 0 x 1
# … with 1 variable: test <chr>
Now let’s make it so that only the order is different:
# A tibble: 4 x 1
test
<chr>
1 A
2 B
3 AC
4 D
# A tibble: 4 x 1
test
<chr>
1 A
2 D
3 AC
4 B
Now that there are no values that are unique to either X or Y, all_equal() reports that there is a different order.
[1] TRUE
[1] "Same row values, but different order"
Remember setequal() ignores order and gives a value of TRUE for no differences.
[1] TRUE
setdiff() also ignores order and shows no differences.
# A tibble: 0 x 1
# … with 1 variable: test <chr>
If we have different column/variable names this makes comparisons more challenging. Columns will be identified for having different names.
all_equal() will simply report that col names are different
[1] "not compatible: \n- Cols in y but not x: `colname2`.\n- Cols in x but not y: `colname1`.\n"
[1] "not compatible: \n- Cols in y but not x: `colname2`.\n- Cols in x but not y: `colname1`.\n"
seteqaul() will report TRUE or FALSE to indicate either a difference in columns or rows
[1] FALSE
setdiff() requires that column names be the same so this will cause an error:
OK, let’s keep going with our data.
How similar are the guidelines tibble and the observed consumption tibbles?
[1] FALSE
OK, looks like we have some different values.
Let’s use the setdiff function to get more information about what is different between the values.
:( That wont work. This is because setdiff() requires that the column names are the same in the objects that we are comparing.
We can use the rename() function from dplyr to do this. We list the value that we want to change to first. We find “food” more intuitive so we are going to change “rei_name” to “food” for the diet_data and the sep_age_diet_data:
# A tibble: 1 x 1
food
<chr>
1 fiber
Great, now we know that the fiber value appears to be different between the two.
Checking our original files we can see that the British spelling “fibre” is used in the table from the article (that we used to create guidelines), in contrast to the the American spelling “fiber” used in the CSV files.
Let’s stick with the American spelling, so we will replace "fibre" in the guideline tibble.
# A tibble: 1 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fiber 19 24 28 g
Now let’s check again to see that our food values match between the guidelines and the observed consumption data tibbles.
# A tibble: 0 x 1
# … with 1 variable: food <chr>
# A tibble: 0 x 1
# … with 1 variable: food <chr>
Great! There are no differences :)
Joining data
Now we can put our guideline data together with the diet_data and the sep_age_diet_data.
Remember that the food data in our guidelines tibble is not necessarily in the same order as that of the consumption data tibbles. Thus this could be a problem if we decided to expand the guidelines rows (to repeat for the number of fruit observations etc.) and add them to our observed consumption tibbles by binding them together by column.

In that case we could use the arrange() function of dplyr to sort the data alphabetically.
However, we will instead use a joining function of dplyr. These functions combine the data together based on common values and don’t require the rows to be in the same order. There are a variety of options.

In our case we would like to retain all of the values of diet_data and sep_age_diet_data. We would like to add new columns of values to these tibbles that correspond to the guideline information about amounts of consumption for each food type in the guidelines tibble. We shouldn’t have any values of food in guidelines that don’t match, so we will not get any NA values. Therefore, in our case any of the mutating join functions should result in the same output.
It’s important to check if we have any overlapping variable names before we join the data. Otherwise, these columns will either be used to identify which rows to join, or new copies of the columns, with a default name to distinguish the columns of one data set from those of the other, will be created. We can use the base R function names() and the intersect() function of the dplyr package to identify which column names are common to our two data sets.
[1] "food" "upper" "lower" "unit"
So it looks like the "upper" , "lower" and "unit" variable names are overlapping. Therefore, to distinguish the names later we will rename the guideline "upper" , "lower" and "unit" variables.
We will again use the rename function from the dplyr package. We can list multiple variables to rename and separate each with a comma. We need to list the new names first.
# A tibble: 15 x 6
direction food lower_optimal optimal upper_optimal unit_optimal
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fruits 200 250 300 g
2 low vegetables 290 360 430 g
3 low legumes 50 60 70 g
4 low whole grains 100 125 150 g
5 low nuts and seeds 16 21 25 g
6 low milk 350 435 520 g
7 high red meat 18 23 27 g
8 high processed meat 0 2 4 g
9 high sugar-sweetened b… 0 3 5 g
10 low fiber 19 24 28 g
11 low calcium 1 1.25 1.5 g
12 low seafood omega-3 f… 200 250 300 mg
13 low polyunsaturated f… 9 11 13 %
14 high trans fatty acids 0 0.5 1 %
15 high sodium 1 3 5 g
It is also a good idea to check our units to make sure they are the same for both guidelines and the observed consumption tibbles(diet_and_guidelines and all_age_diet_and_guidelines).
Let’s take a look with the count() function of the dplyr package. We will also use the bind_cols() function of dplyr to put the data together so that we can see it easily.
# A tibble: 15 x 9
unit...1 food...2 n...3 unit...4 food...5 n...6 unit_optimal food...8 n...9
<chr> <chr> <int> <chr> <chr> <int> <chr> <chr> <int>
1 %energy/… polyunsa… 392 %energy… polyuns… 5880 % polyuns… 1
2 %energy/… trans fa… 392 %energy… trans f… 5880 % trans f… 1
3 g/day calcium 392 g/day calcium 5880 g calcium 1
4 g/day fiber 392 g/day fiber 5880 g fiber 1
5 g/day fruits 392 g/day fruits 5880 g fruits 1
6 g/day legumes 392 g/day legumes 5880 g legumes 1
7 g/day milk 392 g/day milk 5880 g milk 1
8 g/day nuts and… 392 g/day nuts an… 5880 g nuts an… 1
9 g/day processe… 392 g/day process… 5880 g process… 1
10 g/day red meat 392 g/day red meat 5880 g red meat 1
11 g/day seafood … 392 g/day seafood… 5880 g sodium 1
12 g/day sodium 392 g/day sodium 5880 g sugar-s… 1
13 g/day sugar-sw… 392 g/day sugar-s… 5880 g vegetab… 1
14 g/day vegetabl… 392 g/day vegetab… 5880 g whole g… 1
15 g/day whole gr… 392 g/day whole g… 5880 mg seafood… 1
We can see that the only potential issue is the seafood omega-3 fatty acids data which is in g/day for the observed data(diet_data and all_age_diet_and_guidelines), but in mg/day in the guidelines data.
We can account for this by dividing the guidelines seafood omega-3 fatty acids data by 1000 to convert it to grams from milligrams.
To do this we will use the if_else() function in the dplyr package. This allows us to specify a condition (in this case if the unit is "mg"), as well as values if this is condition is met (true), or if the condition is not met (false).
In the following we mutate the values in each of the guideline numeric columns (lower, optimal and upper) one at a time. When we refer to lower for example we refer to the values in the column/variable. So if the condition is not met, then the original value is retained. We will also replace "mg" with "g" after everything is converted to grams.
# A tibble: 15 x 6
direction food lower_optimal optimal upper_optimal unit_optimal
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fruits 200 250 300 g
2 low vegetables 290 360 430 g
3 low legumes 50 60 70 g
4 low whole grains 100 125 150 g
5 low nuts and seeds 16 21 25 g
6 low milk 350 435 520 g
7 high red meat 18 23 27 g
8 high processed meat 0 2 4 g
9 high sugar-sweetened b… 0 3 5 g
10 low fiber 19 24 28 g
11 low calcium 1 1.25 1.5 g
12 low seafood omega-3 f… 0.2 0.25 0.3 g
13 low polyunsaturated f… 9 11 13 %
14 high trans fatty acids 0 0.5 1 %
15 high sodium 1 3 5 g
Click here to see a couple of other ways to do this:
In contrast we could have changed or mutated the values for lower_optimal, optimal, upper_optimal all at once like this using the funs() argument in mutate_at() of dplyr.
Now we are ready to join the data!
Again, we would like to add new columns of values to diet_data and all_age_diet_and_guidelines that correspond to the guideline information about amounts of consumption for each food type in the guidelines tibble. So we will join the data based on the food variable values. We will use the full_join() function of the dplyr package.
Rows: 5,880
Columns: 16
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ location_name <chr> "Global", "Global", "Global", "Global", "Global", "Glo…
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116,…
$ food <chr> "fruits", "fruits", "vegetables", "vegetables", "whole…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All Avail…
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "Female", …
$ parameter <chr> "continuous", "continuous", "continuous", "continuous"…
$ mean <dbl> 8.703202e+01, 9.953182e+01, 1.975187e+02, 1.832338e+02…
$ upper <dbl> 8.988734e+01, 1.023450e+02, 2.083679e+02, 1.921103e+02…
$ lower <dbl> 8.452347e+01, 9.672140e+01, 1.887154e+02, 1.754019e+02…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/day", …
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", "low"…
$ lower_optimal <dbl> 200.0, 200.0, 290.0, 290.0, 100.0, 100.0, 16.0, 16.0, …
$ optimal <dbl> 250.00, 250.00, 360.00, 360.00, 125.00, 125.00, 21.00,…
$ upper_optimal <dbl> 300.0, 300.0, 430.0, 430.0, 150.0, 150.0, 25.0, 25.0, …
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", "g",…
Rows: 88,200
Columns: 16
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, …
$ location_name <chr> "Global", "Global", "Global", "Global", "Global", "Glo…
$ food <chr> "fruits", "fruits", "fruits", "fruits", "fruits", "fru…
$ age_group_id <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 31, 32…
$ age_group_name <chr> "25 to 29", "30 to 34", "35 to 39", "40 to 44", "45 to…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male", "Male"…
$ parameter <chr> "continuous", "continuous", "continuous", "continuous"…
$ mean <dbl> 68.54567, 72.62209, 76.73157, 81.03910, 88.79202, 95.9…
$ upper <dbl> 75.16806, 80.00433, 84.73205, 89.52747, 100.94301, 107…
$ lower <dbl> 63.17081, 66.78018, 71.04691, 73.82734, 80.40971, 86.4…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/day", …
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", "low"…
$ lower_optimal <dbl> 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,…
$ optimal <dbl> 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,…
$ upper_optimal <dbl> 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300,…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", "g",…
It’s always a good idea to check that the values are what you expect after merging.
# A tibble: 15 x 3
food optimal n
<chr> <dbl> <int>
1 calcium 1.25 392
2 fiber 24 392
3 fruits 250 392
4 legumes 60 392
5 milk 435 392
6 nuts and seeds 21 392
7 polyunsaturated fatty acids 11 392
8 processed meat 2 392
9 red meat 23 392
10 seafood omega-3 fatty acids 0.25 392
11 sodium 3 392
12 sugar-sweetened beverages 3 392
13 trans fatty acids 0.5 392
14 vegetables 360 392
15 whole grains 125 392
# A tibble: 15 x 3
food optimal n
<chr> <dbl> <int>
1 calcium 1.25 5880
2 fiber 24 5880
3 fruits 250 5880
4 legumes 60 5880
5 milk 435 5880
6 nuts and seeds 21 5880
7 polyunsaturated fatty acids 11 5880
8 processed meat 2 5880
9 red meat 23 5880
10 seafood omega-3 fatty acids 0.25 5880
11 sodium 3 5880
12 sugar-sweetened beverages 3 5880
13 trans fatty acids 0.5 5880
14 vegetables 360 5880
15 whole grains 125 5880
# A tibble: 15 x 6
direction food lower_optimal optimal upper_optimal unit_optimal
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low calcium 1 1.25 1.5 g
2 low fiber 19 24 28 g
3 low fruits 200 250 300 g
4 low legumes 50 60 70 g
5 low milk 350 435 520 g
6 low nuts and seeds 16 21 25 g
7 low polyunsaturated f… 9 11 13 %
8 high processed meat 0 2 4 g
9 high red meat 18 23 27 g
10 low seafood omega-3 f… 0.2 0.25 0.3 g
11 high sodium 1 3 5 g
12 high sugar-sweetened b… 0 3 5 g
13 high trans fatty acids 0 0.5 1 %
14 low vegetables 290 360 430 g
15 low whole grains 100 125 150 g
Looks good!
Calculating relative consumption
Recall that our aim is to compare the consumption rates of these dietary factors by different groups of people, and ideally, to facilitate cross-factor comparisons, we want to consider consumption rates relative to the optimal guidelines.
To do this, let’s calculate values of consumption that are relative to the suggested guidelines.
There are a few approaches we could take. One is to calculate a "percentage of optimal consumption" using the mean value for each observed factor relative to its optimal value. To do this we will use the mutate() function of the dplyrpackage. This will create a new variable called Relative_Percent that will be equal to the ratio of the mean value and the optimal value, multiplied by 100, to create a percentage relative to the optimal amount suggested.
Another option is to incorporate the range of optimal intakes and the direction that is associated with health risk. If the direction of risk is high and the consumption was greater than the optimal mean value, than the percentage is calculated based on the upper_optimal value, while if the direction of risk is low and the consumption is less than the optimal mean value, then the percentage is calculated based on the lower_optimal value. We will use the case_when() function of the dplyr package to do this. This allows us to specify values (indicated on the right side of the ~symbol) based on specific conditions (indicated on the left side of the ~ symbol). We can specify multiple conditions using the & symbol.
Another option is to create a binary outcome indicating whether optimal consumption was achieved or not.
Rows: 5,880
Columns: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 20…
$ location_name <chr> "Global", "Global", "Global", "Global", "Global", …
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, …
$ food <chr> "fruits", "fruits", "vegetables", "vegetables", "w…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All A…
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "Femal…
$ parameter <chr> "continuous", "continuous", "continuous", "continu…
$ mean <dbl> 8.703202e+01, 9.953182e+01, 1.975187e+02, 1.832338…
$ upper <dbl> 8.988734e+01, 1.023450e+02, 2.083679e+02, 1.921103…
$ lower <dbl> 8.452347e+01, 9.672140e+01, 1.887154e+02, 1.754019…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/da…
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", "…
$ lower_optimal <dbl> 200.0, 200.0, 290.0, 290.0, 100.0, 100.0, 16.0, 16…
$ optimal <dbl> 250.00, 250.00, 360.00, 360.00, 125.00, 125.00, 21…
$ upper_optimal <dbl> 300.0, 300.0, 430.0, 430.0, 150.0, 150.0, 25.0, 25…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ Relative_Percent <dbl> 34.8128083, 39.8127275, 54.8663179, 50.8982797, 23…
$ range_percent <dbl> 43.5160103, 49.7659094, 68.1099118, 63.1840714, 29…
$ percent_over_under <dbl> -56.483990, -50.234091, -31.890088, -36.815929, -7…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No", "N…
Rows: 88,200
Columns: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 20…
$ location_name <chr> "Global", "Global", "Global", "Global", "Global", …
$ food <chr> "fruits", "fruits", "fruits", "fruits", "fruits", …
$ age_group_id <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 31…
$ age_group_name <chr> "25 to 29", "30 to 34", "35 to 39", "40 to 44", "4…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male", "M…
$ parameter <chr> "continuous", "continuous", "continuous", "continu…
$ mean <dbl> 68.54567, 72.62209, 76.73157, 81.03910, 88.79202, …
$ upper <dbl> 75.16806, 80.00433, 84.73205, 89.52747, 100.94301,…
$ lower <dbl> 63.17081, 66.78018, 71.04691, 73.82734, 80.40971, …
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/da…
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", "…
$ lower_optimal <dbl> 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, …
$ optimal <dbl> 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, …
$ upper_optimal <dbl> 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, …
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ Relative_Percent <dbl> 27.41827, 29.04883, 30.69263, 32.41564, 35.51681, …
$ range_percent <dbl> 34.27284, 36.31104, 38.36578, 40.51955, 44.39601, …
$ percent_over_under <dbl> -65.72716, -63.68896, -61.63422, -59.48045, -55.60…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No", "N…
One last thing that can be useful with data wrangling is to reshape the data into what is called the long format. This is very useful for creating visualizations with a powerful and flexible package called ggplot2.
To coerce an object into long format, we create more rows and fewer columns. For a more information about this, please see this case study.
We would like to put together the different types of percentages of the optimal intake that we just calculated.
To get our data in long format we can use the pivot_longer() function of the tidyr package. We will also show how this would be done with the older version of this function, called gather().
For pivot_longer(), we will list the columns that we want to come together into the longer format using the cols argument. For gather() we would simply list the variables that we wish to consolidate. The names_to argument indicates the name of the variable that will include the character information about the values that we are consolidating, i.e., this variable contains the names of the columns that we are bringing together. This is equivalent to the key argument in gather(). The values_to is the name of the column that will contain the values of the columns we are consolidating. This is equivalent to the value argument in gather(). We can use contains() of the tidyr package to look at the variables with names that contain "percent" .
We would get an identical output from the methods. We can check that with setequal().
[1] TRUE
Let’s do the same for the age separated data.
We now have the main variables and data formats that we need to proceed with the next steps of our analysis, including data exploration and eventually, modeling.
Data Exploration
Exploring age collapsed data
Let’s start by taking a look at the percent of consumption, across all dietary factors. Again we will use the base R summary() function:
Relative_Percent
Min. : 0.02
1st Qu.: 11.20
Median : 34.71
Mean : 187.86
3rd Qu.: 73.12
Max. :7693.68
Wow! Some of the values are nearly zero, suggesting that some people are consuming basically zero percent of what is suggested for optimal health. On the other hand, for some dietary factors people are consuming over 7,000 percent what is suggested!
This is why it is important to look at the direction of consumption that could be harmful. For example if there is a population that consumes large amounts of vegetables this could be a good thing, but if there is a population consuming large amounts of sodium this would be a bad thing.
Let’s take a look to see what dietary factors are at the extremes by arranging the data using the arrange() function of the dplyr package. We can arrange by smallest to largest using the default and we can arrange largest to smallest using the minus sign -.
Rows: 5,880
Columns: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 20…
$ location_name <chr> "Costa Rica", "Colombia", "Panama", "Venezuela", "…
$ rei_id <dbl> 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, …
$ food <chr> "sugar-sweetened beverages", "sugar-sweetened beve…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All A…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male", "M…
$ parameter <chr> "continuous", "continuous", "continuous", "continu…
$ mean <dbl> 230.8105, 201.7180, 194.4116, 193.9048, 188.4661, …
$ upper <dbl> 247.9342, 216.9260, 208.8040, 208.8702, 203.3799, …
$ lower <dbl> 215.5919, 189.4812, 181.7150, 180.7209, 174.5476, …
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/da…
$ direction <chr> "high", "high", "high", "high", "high", "high", "h…
$ lower_optimal <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ optimal <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,…
$ upper_optimal <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ Relative_Percent <dbl> 7693.684, 6723.934, 6480.386, 6463.492, 6282.204, …
$ range_percent <dbl> 4616.211, 4034.361, 3888.232, 3878.095, 3769.322, …
$ percent_over_under <dbl> 4516.211, 3934.361, 3788.232, 3778.095, 3669.322, …
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No", "N…
OK, so it looks like sugar-sweetened beverages are really over-consumed in some parts of the world!
Recall from the supplementary table from the article that over-consumption of sugar-sweetened beverages is associated with both Diabetes mellitus type 2 and Ischemic heart disease. This article discusses some of the controversy over the potential health risks associated with high consumption of sugar.
It still looks quite bad if we look at the other calculated percentage values.
Relative_Percent range_percent percent_over_under
Min. : 0.02 Min. : 0.025 Min. : -99.97
1st Qu.: 11.20 1st Qu.: 13.263 1st Qu.: -77.60
Median : 34.71 Median : 38.941 Median : -42.20
Mean : 187.86 Mean : 127.272 Mean : 39.49
3rd Qu.: 73.12 3rd Qu.: 72.414 3rd Qu.: 0.00
Max. :7693.68 Max. :4616.211 Max. :4516.21
So some places are still consuming 4,000 percent more than the upper range of the suggested optimal intake.
Let’s take a look at global levels:
# A tibble: 2 x 20
year_id location_name rei_id food age_group_name sex parameter mean upper
<dbl> <chr> <dbl> <chr> <chr> <chr> <chr> <dbl> <dbl>
1 2017 Global 118 suga… All Available… Male continuo… 65.5 71.0
2 2017 Global 118 suga… All Available… Fema… continuo… 47.7 51.4
# … with 11 more variables: lower <dbl>, unit <chr>, direction <chr>,
# lower_optimal <dbl>, optimal <dbl>, upper_optimal <dbl>,
# unit_optimal <chr>, Relative_Percent <dbl>, range_percent <dbl>,
# percent_over_under <dbl>, opt_achieved <chr>
For those who are less familiar with the metric system where grams are equivalent to milliliters, it may be useful to realize how many fluid ounces the max amount of consumption per day (~248g for the upper value for Costa Rica) actually is.
There are 0.35247 ounces in one gram.
[1] 87.38937
OK, so the top consumers are drinking about 87 fluid ounces per day. Since there are 12 ounces in a single can of soda, this is about 7.25 sodas per day. Globally on average, males are drinking around 1.924 sodas worth of sweetened beverages, while females are drinking about 1.401.
Let’s take a look at what is under-consumed:
Rows: 5,880
Columns: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 20…
$ location_name <chr> "Chad", "Chad", "Mali", "Mali", "Burkina Faso", "B…
$ rei_id <dbl> 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, …
$ food <chr> "polyunsaturated fatty acids", "polyunsaturated fa…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All A…
$ sex <chr> "Female", "Male", "Female", "Male", "Female", "Mal…
$ parameter <chr> "continuous", "continuous", "continuous", "continu…
$ mean <dbl> 0.002227074, 0.002295916, 0.002301266, 0.002373331…
$ upper <dbl> 0.002383410, 0.002439931, 0.002461209, 0.002520039…
$ lower <dbl> 0.002082132, 0.002161922, 0.002152212, 0.002229945…
$ unit <chr> "%energy/day", "%energy/day", "%energy/day", "%ene…
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", "…
$ lower_optimal <dbl> 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,…
$ optimal <dbl> 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11…
$ upper_optimal <dbl> 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13…
$ unit_optimal <chr> "%", "%", "%", "%", "%", "%", "%", "%", "%", "%", …
$ Relative_Percent <dbl> 0.02024613, 0.02087196, 0.02092060, 0.02157574, 0.…
$ range_percent <dbl> 0.02474527, 0.02551018, 0.02556962, 0.02637034, 0.…
$ percent_over_under <dbl> -99.97525, -99.97449, -99.97443, -99.97363, -99.96…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No", "N…
On the other hand, it looks like some places are consuming almost no polyunsaturated fatty acids. These are fats that found in plant-based sources like seeds and nuts. According to an article about polyunsaturated fatty acids and its influence on health:
Coronary heart disease (CHD) is the leading cause of death worldwide … The types of dietary fats consumed play an important role in CHD risk, representing key modifiable risk factors…In particular, higher intakes of trans fat (TFA) and of saturated fat (SFA) replacing ω‐6 (n‐6) polyunsaturated fat (PUFA) are associated with increased CHD… whereas higher intake of PUFA replacing either SFA or carbohydrate is associated with lower risk.
Let’s get an idea about how countries compare in terms of how many of the dietary factors are consumed at the optimal level (the opt_achieved variable).
# A tibble: 2 x 2
opt_achieved n
<chr> <int>
1 No 4360
2 Yes 1520
Looks like overall, only 34.86% of dietary factors for all tested populations were at optimal levels.
Let’s get an idea about how countries compare on this metric.
It looks as though on average the populations (both male and female separately) in Qatar, Rwanda, and Turkey consumed the optimal level of intake for the largest number of dietary factors (13 out of 30 (for the 15 dietary factors for males and females)).
In contrast, the Czech Republic, Greenland, Hungary, Slovakia, Slovenia, and the United States had the poorest consumption rates (27 out of 30 were not at optimal levels).
Let’s look at the raw US data:
Rows: 30
Columns: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 20…
$ location_name <chr> "United States", "United States", "United States",…
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, …
$ food <chr> "fruits", "fruits", "vegetables", "vegetables", "w…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All A…
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "Femal…
$ parameter <chr> "continuous", "continuous", "continuous", "continu…
$ mean <dbl> 114.24773940, 129.11513300, 208.93230110, 192.6563…
$ upper <dbl> 121.37292480, 136.94611510, 217.80223830, 200.7148…
$ lower <dbl> 107.89222320, 122.33941970, 200.05582000, 184.5778…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/da…
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", "…
$ lower_optimal <dbl> 200.0, 200.0, 290.0, 290.0, 100.0, 100.0, 16.0, 16…
$ optimal <dbl> 250.00, 250.00, 360.00, 360.00, 125.00, 125.00, 21…
$ upper_optimal <dbl> 300.0, 300.0, 430.0, 430.0, 150.0, 150.0, 25.0, 25…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ Relative_Percent <dbl> 45.699096, 51.646053, 58.036750, 53.515649, 23.121…
$ range_percent <dbl> 57.123870, 64.557566, 72.045621, 66.433220, 28.901…
$ percent_over_under <dbl> -42.876130, -35.442434, -27.954379, -33.566780, -7…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No", "N…
Let’s see how males and females compare for achieving the optimal intake, across all countries:
# A tibble: 4 x 3
sex opt_achieved n
<chr> <chr> <int>
1 Female No 2171
2 Female Yes 769
3 Male No 2189
4 Male Yes 751
Looks pretty similar, but it may be a bit better for females. We will evaluate this further below.
In order to assess what we have observed so far in a graphical way, we will make some data visualizations. One way we can do this is with the ggplot2 package. The ggplot2 package creates plots by building the plot components piece by piece, using "layers".
With ggplot2 we select what data we would like to plot using the first function (ggplot()) and then we add on additional layers of complexity (these layers can even involve different data). The aes() argument specifies what aspects of the data will be plotted where. The geom_* function specifies what type of plot to create (e.g. geom_histogram() creates a histogram). Notice in the following code how there is a plus sign between the ggplot() function and the geom_bar() function; this is how we combine different plot layers.
We will see later how we can add many layers to plots with ggplot2. For additional information on using ggplot2, see this case study.

Continuing with ggplot2 we will now create a different type of plot. This time we will create a series of box plots. We will use the facet_wrap() function of ggplot2 to allow us to create many different plots simultaneously. In this case we can look at box plots for the different dietary factors colored by sex. The scales argument when set to "free" means that each of the sequential plot created by the facet can have a different scale for the y axis, otherwise, by default they are constrained to the same scale. Since our dietary factors are measured on very different scales, we do not want this constraint here.
# we will create a new variable with food names with new lines
diet_and_guidelines %<>%
mutate(food_to_plot =
str_replace(
string = pull(diet_and_guidelines,food),
pattern = " ",
replacement = "\n"))
diet_and_guidelines %>%
ggplot(aes(y = Relative_Percent ,
x = sex,
color = sex)) +
geom_boxplot() +
facet_wrap(~ food_to_plot,
scales = "free",
#specifies the number of rows of subplots
nrow = 3,
#moves the food label to the right
strip.position = "right") +
#this changes the size of the font for the labels
theme(strip.text.y = element_text(size = 8),
axis.text.x = element_text(angle = 70,
hjust = 1))

If we just look at differences by sex for the specific dietary factors, males appear to potentially consume more of many of the factors, including possibly more sodium, fiber, calcium, red meat, and sugar-sweetened beverages than females. Females may consume more fruit.
Exploring the data separated by age
Now we will take a look at the data that is separated by age groups.
First, recall that we have 15 different age groups starting from age 25 to 95 plus.
# A tibble: 15 x 2
age_group_name n
<chr> <int>
1 25 to 29 5880
2 30 to 34 5880
3 35 to 39 5880
4 40 to 44 5880
5 45 to 49 5880
6 50 to 54 5880
7 55 to 59 5880
8 60 to 64 5880
9 65 to 69 5880
10 70 to 74 5880
11 75 to 79 5880
12 80 to 84 5880
13 85 to 89 5880
14 90 to 94 5880
15 95 plus 5880

We can see from these plots that there appear to be age differences and gender differences for some of the different dietary factors. We will work to create clearer figures later on. However these initial figures have given us a better sense of the data that we are working with.
Data Analysis
Recall what our main questions were:
Our main questions are:
- What are the global trends for potentially harmful diets?
- How do males and females compare?
- How do different age groups compare for these dietary factors?
- How do different countries compare? In particular, how does the US compare to other countries in terms of diet trends?
We have some general sense about global trends for the risk-associated dietary factors, however we want to know more.
We are interested in how much the genders differ, how much the 15 different age groups differ, and how the 195 countries compare.
In order to make inferences about these comparisons, it is helpful to perform statistical tests. These tests can help us to determine the strength of the association between the consumption of the dietary factors (our outcome variable) and sex, age group, and country identity (our predictor variables). One way to look at the strength of association between variables is to use a statistical method called regression.
If we measure consumption using either raw consumption or the percent of optimal consumption, then our outcome variable is what we call continuous, because our values can take on any numeric value within the range of possible values. To look at the strength of association with a continuous outcome, we can use linear regression.
If, instead, we measure consumption by whether or not the optimal level of consumption was achieved (“yes” or “no”), then our outcome would be considered binary, meaning it can take only two possible values. To look at the strength of association with a binary outcome, we can use logistic regression. There are other regression method for different types of outcomes as well; see here for a guide on different types of regression methods.
In this case study, we will focus on the outcome of the percent of optimal consumption (Relative_Percent), so we will focus our analysis on linear regression.
You may have already learned that one can compare a continuous outcome between two groups using a \(t\)-test. For more information on the \(t\)-test see this case study. And perhaps you have heard about ANOVA (ANalysis Of VAriance) for comparing a continuous outcome across more than two groups. It turns out that both the \(t\)-test and ANOVA are specialized types of linear regression. We will use each of these tests to investigate patterns of consumption for dietary factors that contribute to health risk and we will look at how we can obtain equivalent results with regression.
Linear Regression
So what is linear regression? How can we use regression to compare our groups of interest and look at the relationship between group identity and consumption of dietary factors associated with health risk?
The statistical version of the term regression was coined in 1877 in this article about the relationship between hereditary traits and population averages. The author particularly focused on height and kinship or relatedness. The word itself means "to go back to a simpler state". It was noticed that individuals with parents who had an extreme trait, such as exceptional height, tended to have a height more similar to the average of the population than the extreme height of their parents. For example if parents were very tall, their children were likely to be a bit shorter than their parents and therefore closer to the population average. Thus the children regressed towards the mean or in the author’s words the offspring showed:
“a regression towards mediocrity”
See here for more information about this history.
When we think about this from a statistical standpoint, regression allows us to estimate or regress relationships between variables with a “simple” model. We do this by estimating the mean of an outcome, given a value of an input or predictor variable. This can be useful for predicting future values of the outcome based on the approximation of the real relationship between the variables within the model, or just for understanding how different variables are related to one another.
We will start by considering simple linear regression, where we have one continuous predictor variable and one continuous outcome variable, as shown below: 
We want to identify a “best fit” line that summarizes the relationship between these two variables. We can so this using the ordinary least squares method, which chooses the line that best fits the data by minimizing the sum of the squared vertical distances between each point and the line. In the above example, this line turns out to be: 
Fitting a line to the data like this allows us to create a formula for the line using an intercept and a slope, so that we can then estimate mean values of \(Y\) (dependent/outcome variable) given known values of \(X\) (independent/predictor/covariate/explanatory variable(s)). People will also say that we are “regressing \(Y\) on \(X\)”.
You may have seen the formula for a line written like this:
\[Y = mX + b\]
or
\[Y = aX + b\]
In this case \(m\) or \(a\) is the slope of the line and \(b\) is a constant and represents the y-intercept or the point where the y axis is crossed by the line, when \(x = 0\).
In regression, we usually write this model like this:
\[Y = \beta_{1}X +\beta_{0}\]
Now \(\beta_{1}\), called “beta one”“, is our slope and \(\beta_{0}\), called”beta zero" (or “beta naught”), is our intercept. In our example above, the slope of the regression line is \(\beta_{1} = 2.3\) and the intercept is \(\beta_{0} = -6.6\).
Importantly the slope (\(\beta_{1}\)) gives us a quantitative measure of the relationship between the independent variable (\(X\)) on the dependent variable (\(Y\)). In particular, \(\beta_{1}\) tells how the expected difference in the \(Y\) value for a difference of 1 unit in the \(X\) value.
It’s possible that the regression line will perfectly fit the data, and all points will lie on the line with no distance to the line:

In this case, the slope or \(\beta_{1}\) is 1 and the intercept \(\beta_{0}\) is 10 and every observed data point lies exactly on the line, e.g., we can see that when \(X\) is 50, \(Y\) is exactly 60. This is very unusual in statistical analysis however, as often the relationship between variables is more complicated and there is more noise in our data. In these other cases there will be greater distances between the line and the points.
Like this regression: 
In this case, because there is some vertical distance between the line and the data points, there is a bit of what is called “error” in the model. The formula for the relationship between \(X\) and \(Y\) does not perfectly describe the data. The vertical distance between the line and each data point is what we call a residual. Our least squares method finds the line with the minimized value of the sum of the squared residual values.
Check out this interactive explanation of how the ordinary least squares method works.
Here is an image of what we are saying about the ordinary least squares regression to fit a line to data:
This basic concept of simple linear regression an be extended to allow for more than one covariate (the independent variables, or x’s); this is called multivariable linear regression. With more than one independent variable, we can’t visualize these relationships easily with a line on a two-dimensional page, but the mathematical concept remains in some sense the same.
R has it’s own way of representing the regression equation in code. For a guide on how to perform regressions in R see here.
In R we indicate a linear model like this:
Here our response/outcome variable is on the left of the ~ while our covariates/explanatory variables are on the right of the ~.
Before we get started, let’s remove the global values from our data and set them aside, as this is really a composite of all the country values.
\(t\)-test and linear regression
Since we will be covering a lot of different statistical concepts here, we will want to focus are analysis on a single dietary factor. Let’s choose one of the dietary factors that appeared to potentially have a difference between genders based on our figure in our exploratory analysis.
“If we just look at differences by sex for the specific dietary factors, males appear to potentially consume more of many of the factors, including possibly more sodium, fiber, calcium, red meat, and sugar-sweetened beverages than females. Females may consume more fruit.”
Let’s take a look at red meat.
We can compare the relative percent of red meat consumption of males and females around the world using the well known \(t\)-test using the t.test() function and a linear regression model using the lm() function (both are included in stats package that is installed with R by default) and we will get the same results. See here for additional explanation about why that is the case. Here and here are also great sources about how many commonly known statistical tests are specialized forms of regression.
Before we get started, let’s think about the assumptions of both an independent samples \(t\)-test and linear regression.
Independent samples \(t\)-test assumptions:
- Normality of the outcome in each group (this is not as much of an issue if the number of observations is relatively large, i.e., total n > 30 - which is indeed the case for us!)
- Equal variance between the two groups
- Independent observations
Linear regression assumptions:
L (linear) - There is a linear relationship between the outcome variable and each covariate.
I (independent) - The outcome for individual observations are independent from one another, given the covariates in the model.
N (normal) - The residuals (errors) are normally distributed. Note that the variables themselves do not need to be normally distributed.
E (equal variances) - The variance of the residuals is constant across covariate groups. This is called homoscedasticity. In other words the residuals are of similar size along the regression line.
It’s also important that if there are multiple predictor variables, that these are not too highly correlated.
See here for additional information about the assumptions of linear regressions.
Notice that many of the assumptions between \(t\)-tests and linear regression are similar – each has an assumption of normality, equal variance, and independence!
Assessing normality
First we will explore the shape of the distribution of these relative percent of red meat consumption. We can do this by looking at a frequency distribution of the Relative_Percent variable for red meat consumption. We will use the geom_histogram() of the ggplot2package to create a histogram to evaluate the frequency distributions of our data. The facet_wrap() function of the ggplot2 package allows us to look at different parts of our data in separate plots. Here we can compare the distribution for males and females.

This Relative_Percent variable appears to have a right skew for both male and female individuals. We can also see this by looking at normal Quantile-Quantile (Q-Q) plots of this variable. Remember that in a Q-Q plot, points away from the line indicate one of the distributions is more skewed than the other. In this case, we see that the values in are sample are skewed relative to the theoretical normal distribution. Here is a great reference for interpreting Q-Q plots.

We can consider transforming our data to make it more normally distributed. When data is highly right skewed, a log transformation is often helpful.
Let’s take a look a the log (with base 10) of our Relative_Percent variable:


OK, so now our histograms look fairly normal. It isn’t perfect, but we have a large number of samples, so this is good for our \(t\)-test assumptions.
Assessing equal variances
The next thing we need to check is if the variance in red meat consumption is similar between the two gender groups. We can use the var.test() of the stats package using the log-normalized data, as this data is fairly normally distributed.
Because we are piping in our data to this test function, we need to indicate that this is the data we intend to use by using . for the data argument. This is a handy tip when piping into a function outside of the tidyverse where the first argument isn’t a data set.
F test to compare two variances
data: log10(Relative_Percent) by sex
F = 0.96369, num df = 194, denom df = 194, p-value = 0.797
alternative hypothesis: true ratio of variances is not equal to 1
95 percent confidence interval:
0.7266925 1.2779719
sample estimates:
ratio of variances
0.963687
The p value > .05 for this test, thus we can conclude that there is not enough evidence to reject the null hypothesis that there is no difference in the variance of the distributions, so we conclude that variance is roughly equal.
Comparing a \(t\)-test to linear regression
Now let’s compare the consumption of red meat across genders using both a \(t\)-test and a linear regression. First our independent samples \(t\)-test:
Two Sample t-test
data: log10(Relative_Percent) by sex
t = -5.3187, df = 388, p-value = 1.77e-07
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-0.2525474 -0.1162266
sample estimates:
mean in group Female mean in group Male
1.798872 1.983259
Notice here that sample means for the two groups are 1.80 and 1.98 for males and females, respectively. So that means the difference in sample means is 1.80 - 1.98 = -0.18. We also see a test statistic of \(t\) = -5.32 and a very small \(p\)-value.
Let’s examine the same relationship using linear regression:
Call:
lm(formula = log10(Relative_Percent) ~ sex, data = .)
Residuals:
Min 1Q Median 3Q Max
-1.0238 -0.2484 0.0052 0.3127 0.6170
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.79887 0.02451 73.382 < 2e-16 ***
sexMale 0.18439 0.03467 5.319 1.77e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.3423 on 388 degrees of freedom
Multiple R-squared: 0.06795, Adjusted R-squared: 0.06555
F-statistic: 28.29 on 1 and 388 DF, p-value: 1.77e-07
Look at the results for the slope of the regression line, indicated by the sexMale row in the output above. Notice how the \(t\)-value and the \(p\)-value match our \(t\)-test! (Well, the signs are switched in each case – the \(t\) value is negative in the t.test() output because the male group is being used as reference group, while the female group is being used as the reference group in lm()). We can fix this using the fct_inorder() function of the forcats package which is all about factors. This function allows us to order the factor by what appears first. In this case “male” appears first, so now our output will match that of the lm() function.
Call:
lm(formula = log10(Relative_Percent) ~ sex, data = .)
Residuals:
Min 1Q Median 3Q Max
-1.0238 -0.2484 0.0052 0.3127 0.6170
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.79887 0.02451 73.382 < 2e-16 ***
sexMale 0.18439 0.03467 5.319 1.77e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.3423 on 388 degrees of freedom
Multiple R-squared: 0.06795, Adjusted R-squared: 0.06555
F-statistic: 28.29 on 1 and 388 DF, p-value: 1.77e-07
Two Sample t-test
data: log10(Relative_Percent) by sex
t = 5.3187, df = 388, p-value = 1.77e-07
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
0.1162266 0.2525474
sample estimates:
mean in group Male mean in group Female
1.983259 1.798872
Now they match. Notice that the degrees of freedom also match, both results show 388 degrees of freedom. We are estimating two parameters for the linear model the two \(\beta\) coefficients, (the slope and intercept), and for the \(t\)-test we are estimating the means of two groups (males and females). Overall we have two samples (male and female) for each of the 195 countries.
Thus, the overall sample number is: \(n = 195*2 = 390\)
\[df = n - # parameters estimating\] Thus the degrees of freedom can be calculated as: \(df = 390 -2 = 388\)
Let’s look more closely at the linear regression output from lm(). Our estimated intercept (\(\beta_{0}\)) is 1.80, which can be interpreted as the mean value when sex is not male (so in this case when sex is female). This matches the sample mean of the female group in the t.test() output.
Our estimated slope (\(\beta_{1}\)) is 0.18, which can be interpreted as the slope of the regression line or the mean change in \(Y\) associated with one-unit increase in \(X\). Since our \(X\) variable is sex, a one-unit change means moving from one group to another. So we can think of the slope as the difference between the means of the two groups, male (\(X\)=1) minus female (\(X\) = 0). If we calculate this difference in means as calculated in the t.test() output, we get the value of \(\beta_{1}\) (the slope or the sexMale estimate) of the lm() output!
Mean of males - Mean of females \(1.983259 - 1.798872 =0.184387\)
Cool! For more information about the output of lm() see here.
After fitting our linear regression model, we can use the base plot() function to get information about our the model residuals to help us assess whether any of the assumptions of linear regression are violated. Here we choose to view the first three of these plots with which = 1:3.



The second plot shows us that our residuals are slightly negatively (or left) skewed. We can see also see the spread of the residuals is similar between males and females, as the first and third plot show similar spreads of values in the two lines. This suggests that the assumption of homoscedasticity is met. Here is what these plots would look like if the variance were not the same between the groups:



In this case the spread of the points is clearly less for one group compared to the other. If we saw plots like these, we would be concerned the assumption of homoscedasticity was violated.
Assessing independence
We never considered the assumption of independent required by both a \(t\)-test and linear regression. Do we truly have independent samples in this case? No! Since we have female and male values from the same countries, our data is really what we would call “paired”. The male and female diet values from the same country are most likely related to each another because of cultural effects on diet. This means the assumption of independence for the independent samples \(t\)-test is violated, as is the independence assumption for linear regression.
We can address this by doing a paired \(t\)-test instead of an independent \(t\)-test and by accounting for country in our linear model by adding it to our model as what we call a fixed effect.
Paired \(t\)-test and linear model with fixed effects
Now will perform the paired versions of our analysis. This is very easy to do with the t.test() function, by simply using the paired argument and setting it equal to TRUE.
However, our data needs to be in a slightly different form to do the paired test, since we have to tell R which values need to be paired together. Instead of one long dataset with different rows for males and females, we will need separate columns for the male and female values. So we need to make our dataset wider. We can do that using the pivot_wider() function of the tidyr package. To use this function we specify the values that we want to separate into more variables using the values_from argument and we use the names_from argument to specify how we want to separate these other variables. In this case we will make a male and female version of all the other variables specified.
Rows: 2,925
Columns: 26
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2…
$ location_name <chr> "China", "China", "China", "China", "China"…
$ rei_id <dbl> 111, 112, 113, 114, 115, 116, 117, 118, 119…
$ food <chr> "fruits", "vegetables", "whole grains", "nu…
$ age_group_name <chr> "All Available Ages", "All Available Ages",…
$ parameter <chr> "continuous", "continuous", "continuous", "…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day"…
$ direction <chr> "low", "low", "low", "low", "low", "high", …
$ lower_optimal <dbl> 200.0, 290.0, 100.0, 16.0, 350.0, 18.0, 0.0…
$ optimal <dbl> 250.00, 360.00, 125.00, 21.00, 435.00, 23.0…
$ upper_optimal <dbl> 300.0, 430.0, 150.0, 25.0, 520.0, 27.0, 4.0…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g"…
$ Relative_Percent_Male <dbl> 30.1276714, 69.9780163, 20.5969990, 9.55243…
$ Relative_Percent_Female <dbl> 34.3698972, 65.4711643, 19.2030299, 8.98597…
$ range_percent_Male <dbl> 37.6595893, 86.8692617, 25.7462488, 12.5375…
$ range_percent_Female <dbl> 42.9623715, 81.2745488, 24.0037874, 11.7940…
$ percent_over_under_Male <dbl> -62.34041, -13.13074, -74.25375, -87.46243,…
$ percent_over_under_Female <dbl> -57.03763, -18.72545, -75.99621, -88.20590,…
$ mean_Male <dbl> 7.531918e+01, 2.519209e+02, 2.574625e+01, 2…
$ mean_Female <dbl> 8.592474e+01, 2.356962e+02, 2.400379e+01, 1…
$ upper_Male <dbl> 8.658295e+01, 2.946774e+02, 2.723223e+01, 2…
$ upper_Female <dbl> 9.759191e+01, 2.720864e+02, 2.541951e+01, 2…
$ lower_Male <dbl> 6.543868e+01, 2.153508e+02, 2.426562e+01, 1…
$ lower_Female <dbl> 7.531231e+01, 2.033138e+02, 2.262773e+01, 1…
$ opt_achieved_Male <chr> "No", "No", "No", "No", "No", "No", "Yes", …
$ opt_achieved_Female <chr> "No", "No", "No", "No", "No", "No", "Yes", …
You can see we now have a Relative_Percent_Male variable and a Relative_Percent_Female variable. We can use these two variables in our paired \(t\)-test. Since the paired version of the \(t\)-test doesn’t take a data= argument, we will pull the appropriate variables from our data a little bit differently, using the pull() function.
Paired t-test
data: log10(pull(filter(wide_diet, food == "red meat"), Relative_Percent_Male)) and log10(pull(filter(wide_diet, food == "red meat"), Relative_Percent_Female))
t = 188.16, df = 194, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
0.1824542 0.1863197
sample estimates:
mean of the differences
0.184387
Here an estimated mean difference (Males - Females) of 0.18, and that this is considered significantly different than 0 due to a very small \(p\)-value. You can also see that now our degrees of freedom are 194, which makes sense because with paired samples we are only estimating one parameter (the mean difference) based on data on 195 differences for each country. So \(df = n - \# \ parameters = 195 -1 = 194\).
The paired version of the linear model is a bit more complex. In this case we will add another term in our model to evaluate the influence of sex on Relative_Percent consumption while keeping the country identity fixed or constant, or in other words controlling/adjusting for country. We can use the + to add this additional term. Now that we have multiple covariate/explanatory variable terms, we would call this a multivariable linear regression.
So now our model in words will be:
Mean relative consumption of red meat is dependent on sex and country. Or in other words, sex and location influence the consumption of red meat around the world.
Then the coefficient for sex will be different from what we had in our previous lm() model, as it will be calculated while keeping location_name or the country where the consumption value was obtained fixed, or in other words “controlling for location_name.” This will also result in output for each of the countries. The coefficients here represent the average difference in consumption value for each country compared to the reference country of Afghanistan, while accounting for sex.
This now should meet the assumption of independence for a linear regression model, since observations will be independent conditional an the covariates of sex and country.
Let’s fit this model and look at the results.
First let’s look at the estimated coefficient for the sexMale variable, which is 0.18. This can be interpreted as the difference in mean log relative percent consumption between males and females, holding country constant. So comparing males to females within the same country. Notice this is the same estimated difference we found from our paired \(t\)-test! The \(p\)-value for this coefficient also matches the \(p\)-value from the paired \(t\)-test.
You can also see from this output that we have a coefficient for every country except Afghanistan, which is our reference country. These coefficients compare the country to that reference. So the estimated coefficient for location_nameAlbania, 0.44, can be interpreted as the difference in mean log relative percent consumption between Albania and Afghanistan, holding sex constant. So comparing Albania to Afghanistan within males or comparing Albania to Afghanistan within females.
Finally, you might notice that the number of residual degrees of freedom for this regression is 194, just as in the paired \(t\)-test. This makes sense since we have to estimate a coefficient for 194 countries (all except Afghanistan) as well as a coefficient for sex and an intercept. So we have:
\[df = n - # parameters estimating = 390 - 194 - 2 = 194\]
We should also check the residual plots for this fixed effects regression model.



These residual plots look much better than our previous plots. This guide provides more information on how to interpret these residual diagnostic plots.
Based on our Q-Q plot, we appear to have some outliers perhaps at the extreme ends of our tails but overall the residuals look fairly normal. The residual vs fitted plot shows us if the relationship between our outcome variable and our predictors looks linear, if there is unequal error variance between groups, and if there are possible outliers. Ideally this should look like a band of points equally centered around zero. Here are examples of these plots that might show issues of concern.
Overall our plot looks fairly good. The shape of our data looks fairly linear (the residuals don’t appear to have a shape other than a band or line), there does not appear to be any extreme outliers (no data points are especially far away) and the points have the same general range around the line for the various fitted values. There are a few points with wider residuals at the higher fitted values, but overall this looks quite reasonable.
Our scale-location plot also shows us that our variance looks fairly equal across groups as our values show a relatively even spread. A larger bend in the line would indicate more variation in the variance across our independent variable groups also known as heteroscedasticity. There is only a slight bend in the line for our data suggestive of homoscedasticity. So our assumptions look pretty good:
- Linear - the relationship appears to be fairly linear
- Independence - now that we have taken care of the location structure in our data, our samples are independent
- Normality - the residuals appear to be fairly normally distributed and we have a large number of samples to help account for minor violations
- Equal variance - the variance in the residuals appear to be fairly equal across the groups of the independent/predictor variables
Paired \(t\)-test and linear model with mixed effects
To “pair” our data using fixed effects cost us an additional 194 variables in our regression model, one for each country except Afghanistan. Alternatively, we can perform a slightly different type of regression that still accounts for the paired structure in the data.
In this case we will use the lmer() function of the lme4 package. This function allows us to fit what is called a linear mixed effects regression model. We will also use the lmerTest package, since this adds test statistics and \(p\)-values to the linear mixed effects model output.
This type of regression is called mixed because it contains both fixed and random effects. There are many different definitions for fixed and random effects and the difference is conceptually complex and context specific.
However in simplistic terms, fixed effects are generally speaking the variables of interest that we have reason to believe explain or predict the outcome or response variable, while random effects are those that may introduce additional variance in the influence of those predictor variables on the outcome variable. For example, they may provide information about group or batch structures within the data.
In our case, we are interested in the influence of sex on the consumption of red meat, however the identity of the country where the male and female consumption values were obtained may influence this relationship and we would like to control for that. We don’t want to model for location_name itself, but just model it’s influence on the relationship of sex on consumption of red meat. In other words, we are interested in getting a sense of how sex influences consumption rates in general and we want to account for the paired structure within our data, the fact that we have corresponding consumption values for the two sexes from different countries. The notation for including a random effect like this is 1 | variable_name. The one indicates a varying-intercept group effect, in other words we expect that the intercept may vary for each value of the variable indicated to the right of the |. So in our case, the intercept (log relative percent consumption when sex is assigned to the zero value - female) may be different for each country.
Let’s fit a mixed effects model that includes a fixed effect for sex and a random intercept for country:
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: log10(Relative_Percent) ~ sex + (1 | location_name)
Data: .
REML criterion at convergence: -969.5
Scaled residuals:
Min 1Q Median 3Q Max
-3.2253 -0.3914 -0.0038 0.3993 3.2527
Random effects:
Groups Name Variance Std.Dev.
location_name (Intercept) 1.171e-01 0.342181
Residual 9.363e-05 0.009676
Number of obs: 390, groups: location_name, 195
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 1.79887 0.02451 194.15514 73.38 <2e-16 ***
sexMale 0.18439 0.00098 194.00000 188.16 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
sexMale -0.020
How would we interpret the results of this model? Again, let’s look at the estimated coefficient for the sexMale variable, which is 0.18. This can be interpreted the same way as in the simple linear regression, as the difference in mean log relative percent consumption between males and females. However, here we haven’t violated the independence assumption because we are accounting for the paired nature of the data through the random effect for country. The \(t\)-statistic and \(p\)-value for this coefficient also match those from the paired \(t\)-test we did before:
Paired t-test
data: log10(pull(filter(wide_diet, food == "red meat"), Relative_Percent_Male)) and log10(pull(filter(wide_diet, food == "red meat"), Relative_Percent_Female))
t = 188.16, df = 194, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
0.1824542 0.1863197
sample estimates:
mean of the differences
0.184387
Notice that in the output for the mixed effects model, there are not coefficients for each country, like there were in the fixed effects model. This is because we are not explicitly estimating individual country effects in this model. Instead, the country effect is captured through the intercept in this model. Our estimated intercept is 1.80 and the standard deviation of this intercept is 0.34 (shown in the Random effects table in the output.) We can interpret this as saying that each country has an intercept that comes from a normal distribution with mean of 1.80 and a standard deviation of 0.34. Since the intercept in this model represent the log relative percent consumption for females, this give us an idea of how female consumption varies across countries – average log consumption across countries is 1.80, but there is variability from one country to another. And then the male log consumption is, on average, 0.18 higher than for females.
It is more complicated to calculate the degrees of freedom in the mixed effect model and beyond this case study, but it is based on the Satterthwaite formula and results in the same degrees of freedom.
Finally, lets see what our residual plots look like for this mixed effects model. We can’t use the plot() function with a lmer() model to get all of the plots at once, but we can construct a residual vs. fitted value plot and a Q-Q plot ourselves:


Notice that the plots look very similar to what we saw with the fixed effects model.
We see that the paired \(t\)-test, the fixed effects model adjusting for country, and the mixed effects model with a random intercept for country all give the same results in this case. So which test should we use? The decision of which test to perform depends on your question of interest. In this case we were particularly interested in the influence of sex, so setting location_name to a random effect provides the same level of detail about sex without as much information about location_name, so that might be ideal. As we can see, the results, in this case, are the same. The benefit of using regression over a simple paired \(t\)-test would be the ability to add other covariates to our model if we wanted to adjust for other country characteristics.
Overall, though, we can conclude from these tests that we have enough evidence to reject the null hypothesis that there is no difference between the mean consumption of males and females ( or that sex has no association or influence on red meat consumption.) Therefore, it appears that males consume significantly more red meat than females globally.
ANalysis Of VAriance (ANOVA) test
We are also interested in the influence of age group on dietary consumption, but because there are 15 age groups we can’t assess the influence of age group on consumption using the paired \(t\)-test, as this test can only compare 2 groups.
If we wanted to test the hypothesis that there are any age group differences, that at least one of the groups is different from the others; we could use an ANOVA test. This test allows us to compare means of 3 or more groups by evaluating the variance of the data within the groups and among the groups.
Our null hypothesis is that all age groups have equal means: \[ H_0: \mu_{1} = \mu_{2} =\mu_{3}=\mu_{4} = ... \mu_{15} \]
The alternative hypothesis is that at least one age group mean is not equal to the others.
Importantly, if we reject the null, we do not know which group means are different from one another. Subsequent testing is required if we want to know this information. In this case we call this type of non-specific hypothesis an “omnibus” hypothesis.
You could actually perform an ANOVA to compare two means, but in this case you would get an \(F\)-statistic instead of a \(t\)-statistic which would be equivalent to \(t^2\). However it is not conventional to use ANOVA for only 2 means. The \(F\)-statistic is derived form the \(F\)-test is used for a few different type of tests. In the ANOVA the F-test is calculated as:
\[F = \frac{
variability\ between\ the \ groups}{
variablity\ within\ the \ groups}\]
The larger the ratio, the larger the variability between the groups, thus the more likely that the data for each group comes from a different distribution with different means, suggesting that the groups are different.
It turns out that the ANOVA test is also equivalent to linear regression. We will demonstrate this by evaluating how the consumption of red meat varies by age group using an ANOVA and a linear regression.
Thinking about how we want to know if red meat consumption differs between age groups from the linear regression perspective, we could also describe our null hypothesis as:
There is no influence of age group identity on consumption or there is no relationship between age group identity and consumption.
And we could describe our alternative hypothesis as:
Age group identity does influence consumption or explain some of the variation in consumption.
ANOVA assumptions
The ANOVA assumptions are quite similar to the \(t\)-test assumptions:
- Normality of the data for all tested groups (less of an issue if the number of observations is relatively large total n > 30)
- Equal variance between the groups - aka Homogeneity of Variances assumption (make sure you do the correct test if the data is not normal)
- Independent observations
let’s evaluate our assumptions for the groups we are comparing, starting with normality using Q-Q plots. First let’s make age_group_name a factor:
Now let’s look at Q-Q plots of both relative percent consumption and the log-transformed version of this variable:


After transformation, these Q-Q plots look pretty good.
Now let’s look at the assumption of constant variance. There are different ways to assess this assumption across more than two groups. Bartlett’s test works well if the data appears to be quite normally distributed, while the Fligner-Killeen test is nonparametric and does not assume normality of the data.
We will use another popular test, Levene’s test, which is more robust to violations of normality than the Bartlett’s test, but not as robust as the Fligner-Killeen test. The null hypothesis of this test, as for the other two tests, is that the variances are equal across all of the groups. The alternative hypothesis is that at least one pair of groups has different variances. In symbols we would write this as
\[ H_0: \sigma_1^2 = \sigma_2^2 = \sigma_3^2 ... = \sigma_n^2 \]
and
\[H_a:\sigma_i^2 \neq \sigma_j^2 \] for at least one pair (\(i\),\(j\)).
We will use the leveneTest() function of the car package to performs Levene’s test.
Levene's Test for Homogeneity of Variance (center = median)
Df F value Pr(>F)
group 14 0.484 0.9429
5835
Our data does not appear to violate the homogeneity of variances assumption as our \(p\)-value was greater than 0.05 and so we would fail to reject the null hypothesis of equal variances.
We already know that our independence assumption is not met, since the data for the different age groups comes from the same countries. We will account for this in later models, but first let’s compare the results between ANOVA and linear regression assuming the independence assumption is met.
ANOVA and linear regression
We can use the aov() function of the stats package to perform an ANOVA test. We will be performing what is called a one-way ANOVA because we only have one independent variable (age group). We will also perform a linear regression for comparison.
We can see that the \(F\)-statistic (\(F\) value in the aov() output and at the bottom of the lm() output) is the same for both models and the \(p\)-value for the \(F\)-statistic is the same!
We also see that the degrees of freedom for the \(F\)-statistic is 14. This makes sense because we have 15 different age groups and degrees of freedom for the \(F\)-statistic are calculated as \(df = n - 1\). So in our case: \(df = 15 -1\).
The difference here is that with the lm() model we also get information about how the individual age groups are associated with the log relative percent consumption of red meat. Notice that if we look at all the age groups in the data
# A tibble: 15 x 1
age_group_name
<fct>
1 25 to 29
2 30 to 34
3 35 to 39
4 40 to 44
5 45 to 49
6 50 to 54
7 55 to 59
8 60 to 64
9 65 to 69
10 70 to 74
11 75 to 79
12 80 to 84
13 85 to 89
14 90 to 94
15 95 plus
we see that our lm() results are missing one of the age groups, the 25 to 29 age group. That is because this is the reference group and the coefficients indicate the slope or difference in log relative percent consumption rates for each listed age group compared to this reference group.
ANOVA and linear regression with fixed effects
Now let’s account for the paired location_name structure within our data, since the above models violate the independence assumptions for ANOVA and linear regression. We can do this by adding another fixed effect to both the ANOVA model and the linear regression model. For ANOVA, this means we are now doing a two-way ANOVA, since we have two independent variables (age group and country). For linear regression, we are now adding a fixed effect for country to our model.
It’s hard to see that these results match, since the linear regression output doesn’t print the \(F\)-statistic for the age groups together or the countries together; it only gives results for individual \(t\)-tests of each regression coefficient. We can get these grouped \(F\)-statistics using the anova() function of the stats package. This function does not actually directly perform ANOVA like the aov() function, but instead prints a variance table using a lm() object.
Analysis of Variance Table
Response: log10(Relative_Percent)
Df Sum Sq Mean Sq F value Pr(>F)
age_group_name 14 47.64 3.4029 376.12 < 2.2e-16 ***
location_name 194 819.66 4.2250 466.99 < 2.2e-16 ***
Residuals 5641 51.04 0.0090
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
We can see that indeed the \(F\)-values and \(p\)-values from linear regression match those from ANOVA. In this case, this analysis suggests that there is a significant relationship between age group and consumption, even when controlling for country. It also suggests that there is a significant relationship between country and consumption, even when controlling for age group. However, only the first relationship is our relationship of interest; the second is only included in the model to account for the dependent nature of the data.
Remember, the ANOVA results indicate that the means are different across these groups, but it does not inform us about which groups are different. However, the original lm() output using the `summary()~ command gives more information about specific group differences. Remember, though, that these are relative to the reference level for the age group and location and that these values are calculated for the effect on consumption while controlling for the other variable in the model.
ANOVA and linear regression with mixed effects
We could instead perform a similar analysis as we did for the two group analysis where we controlled for the paired data structure using a random effect based on country In particular, we could include a random intercept for country. We could do this within the aov() function using Error() and within the lmer() function with 1 | variable_name.
Modeling all groups of interest
Now we can extend out model to include include sex, age_group_name and location_name all in the same linear model and get information about how each of these factors influences dietary consumption, while accounting for the other factors. Since we are primarily interested in the effects of sex and age, but want to account for the dependence in the data due to repeated measurements by country, we will include sex and age_group_name as fixed effects and incorporate a random intercept for location_name.
Type III Analysis of Variance Table with Satterthwaite's method
Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
sex 46.663 46.663 1 5640 60171 < 2.2e-16 ***
age_group_name 47.641 3.403 14 5640 4388 < 2.2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: log10(Relative_Percent) ~ sex + age_group_name + (1 | location_name)
Data: .
REML criterion at convergence: -23461.2
Scaled residuals:
Min 1Q Median 3Q Max
-4.5195 -0.2671 0.0359 0.2563 9.1685
Random effects:
Groups Name Variance Std.Dev.
location_name (Intercept) 0.1408091 0.37525
Residual 0.0007755 0.02785
Number of obs: 5850, groups: location_name, 195
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 1.905e+00 2.691e-02 1.951e+02 70.801 < 2e-16 ***
sexMale 1.786e-01 7.282e-04 5.640e+03 245.299 < 2e-16 ***
age_group_name30 to 34 -3.525e-03 1.994e-03 5.640e+03 -1.768 0.077178 .
age_group_name35 to 39 -6.997e-03 1.994e-03 5.640e+03 -3.509 0.000454 ***
age_group_name40 to 44 -1.604e-02 1.994e-03 5.640e+03 -8.043 1.06e-15 ***
age_group_name45 to 49 -3.227e-02 1.994e-03 5.640e+03 -16.182 < 2e-16 ***
age_group_name50 to 54 -5.005e-02 1.994e-03 5.640e+03 -25.099 < 2e-16 ***
age_group_name55 to 59 -6.940e-02 1.994e-03 5.640e+03 -34.800 < 2e-16 ***
age_group_name60 to 64 -9.144e-02 1.994e-03 5.640e+03 -45.851 < 2e-16 ***
age_group_name65 to 69 -1.167e-01 1.994e-03 5.640e+03 -58.514 < 2e-16 ***
age_group_name70 to 74 -1.425e-01 1.994e-03 5.640e+03 -71.443 < 2e-16 ***
age_group_name75 to 79 -1.694e-01 1.994e-03 5.640e+03 -84.930 < 2e-16 ***
age_group_name80 to 84 -2.288e-01 1.994e-03 5.640e+03 -114.753 < 2e-16 ***
age_group_name85 to 89 -2.351e-01 1.994e-03 5.640e+03 -117.875 < 2e-16 ***
age_group_name90 to 94 -2.387e-01 1.994e-03 5.640e+03 -119.708 < 2e-16 ***
age_group_name95 plus -2.392e-01 1.994e-03 5.640e+03 -119.958 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Looking at the anova() output, we can see that sex and age group both have significant associations with the consumption of red meat, when controlling for the other variable. Additionally, by looking at the individual coefficient estimates in the summary() output, we see that males tend to have higher red meat consumption compared to females (positive coefficient for sexMale) and that consumption seems to decrease with increasing age (negative coefficients for all the age group categories that appear to become larger in magnitude with increasing age).
LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBFeHBsb3JpbmcgZ2xvYmFsIHBhdHRlcm5zIG9mIGRpZXRhcnkgYmVoYXZpb3JzIGFzc29jaWF0ZWQgd2l0aCBoZWFsdGggcmlzayAiCmNzczogc3R5bGUuY3NzCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgc2VsZl9jb250YWluZWQ6IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCgotLS0KPHN0eWxlPgojVE9DIHsKICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9pbWcvbG9nby5qcGciKTsKICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47CiAgcGFkZGluZy10b3A6IDI0MHB4ICFpbXBvcnRhbnQ7CiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsKfQo8L3N0eWxlPgoKCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjYWNoZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIsIG91dC53aWR0aCA9ICc5MCUnKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkoa25pdHIpCmBgYAoKCgojIyMjIHsub3V0bGluZSB9CmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iODAwIHB0eCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJtYWlucGxvdC5wbmciKSkKYGBgCgoKIyMjIyB7LmRpc2NsYWltZXJfYmxvY2t9CgoqKkRpc2NsYWltZXIqKjogVGhlIHB1cnBvc2Ugb2YgdGhlIFtPcGVuIENhc2UgU3R1ZGllc10oaHR0cHM6Ly93d3cub3BlbmNhc2VzdHVkaWVzLm9yZyl7dGFyZ2V0PSJfYmxhbmsifSBwcm9qZWN0IGlzICoqdG8gZGVtb25zdHJhdGUgdGhlIHVzZSBvZiB2YXJpb3VzIGRhdGEgc2NpZW5jZSBtZXRob2RzLCB0b29scywgYW5kIHNvZnR3YXJlIGluIHRoZSBjb250ZXh0IG9mIG1lc3N5LCByZWFsLXdvcmxkIGRhdGEqKi4gQSBnaXZlbiBjYXNlIHN0dWR5IGRvZXMgbm90IGNvdmVyIGFsbCBhc3BlY3RzIG9mIHRoZSByZXNlYXJjaCBwcm9jZXNzLCBpcyBub3QgY2xhaW1pbmcgdG8gYmUgdGhlIG1vc3QgYXBwcm9wcmlhdGUgd2F5IHRvIGFuYWx5emUgYSBnaXZlbiBkYXRhIHNldCwgYW5kIHNob3VsZCBub3QgYmUgdXNlZCBpbiB0aGUgY29udGV4dCBvZiBtYWtpbmcgcG9saWN5IGRlY2lzaW9ucyB3aXRob3V0IGV4dGVybmFsIGNvbnN1bHRhdGlvbiBmcm9tIHNjaWVudGlmaWMgZXhwZXJ0cy4gCgojIyMjCgojIyMjIHsubGljZW5zZV9ibG9ja30KClRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob25Db21tZXJjaWFsIDMuMCBbKENDIEJZLU5DIDMuMCldKGh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy8zLjAvdXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICBVbml0ZWQgU3RhdGVzIExpY2Vuc2UuCgojIyMjCgojIyMjIHsucmVmZXJlbmNlX2Jsb2NrfQoKVG8gY2l0ZSB0aGlzIGNhc2Ugc3R1ZHkgcGxlYXNlIHVzZToKCldyaWdodCwgQ2FycmllLCBhbmQgT250aXZlcm9zLCBNaWNoYWVsIGFuZCBKYWdlciwgTGVhaCBhbmQgVGF1YiwgTWFyZ2FyZXQgYW5kIEhpY2tzLCBTdGVwaGFuaWUuICgyMDIwKS4gaHR0cHM6Ly93d3cub3BlbmNhc2VzdHVkaWVzLm9yZy9vY3MtYnAtZGlldC8uIE1lbnRhbCBIZWFsdGggb2YgQW1lcmljYW4gWW91dGggKFZlcnNpb24gdjEuMC4wKS4KCiMjIyMKCiMjICoqTW90aXZhdGlvbioqCioqKgoKQW4gW2FydGljbGVdKGh0dHBzOi8vd3d3LnRoZWxhbmNldC5jb20vYWN0aW9uL3Nob3dQZGY/cGlpPVMwMTQwLTY3MzYlMjgxOSUyOTMwMDQxLTgpe3RhcmdldD0iX2JsYW5rIn0gcmVjZW50bHkgcHVibGlzaGVkIGluIFRoZSAKTGFuY2V0IGV2YWx1YXRlZCBnbG9iYWwgZGlldGFyeSB0cmVuZHMgYW5kIHRoZSByZWxhdGlvbnNoaXAgb2YgZGlldGFyeSBmYWN0b3JzIHdpdGggbW9ydGFsaXR5IGFuZCBmZXJ0aWxpdHkuCgpgYGB7ciwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAidGhlcGFwZXIucG5nIikpCmBgYAoKIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30KR0JEIDIwMTcgRGlldCBDb2xsYWJvcmF0b3JzLiBIZWFsdGggZWZmZWN0cyBvZiBkaWV0YXJ5IHJpc2tzIGluIDE5NSBjb3VudHJpZXMsIDE5OTDigJMyMDE3OiBhIHN5c3RlbWF0aWMgYW5hbHlzaXMgZm9yIHRoZSBHbG9iYWwgQnVyZGVuIG9mIERpc2Vhc2UgU3R1ZHkgMjAxNy4gKlRoZSBMYW5jZXQqIDM5MywgMTk1OOKAkzE5NzIgKDIwMTkpLgoKIyMjIwoKVGhpcyBhcnRpY2xlIGV2YWx1YXRlZCBmb29kIGNvbnN1bXB0aW9uIHBhdHRlcm5zIGluIDE5NSBjb3VudHJpZXMgZm9yIDE1IGRpZmZlcmVudCBkaWV0YXJ5IHJpc2sgZmFjdG9ycyB0aGF0IGhhdmUgcHJvYmFibGUgYXNzb2NpYXRpb25zIHdpdGggbm9uLWNvbW11bmljYWJsZSBkaXNlYXNlIChOQ0QpLiBGb3IgZXhhbXBsZSwgb3Zlci1jb25zdW1wdGlvbiBvZiBzb2RpdW0gaXMgYXNzb2NpYXRlZCB3aXRoIGhpZ2ggYmxvb2QgcHJlc3N1cmUuIFRoZXNlIGNvbnN1bXB0aW9uIGxldmVscyB3ZXJlIHRoZW4gdXNlZCB0byBlc3RpbWF0ZSBsZXZlbHMgb2YgbW9ydGFsaXR5IGFuZCBtb3JiaWRpdHkgZHVlIHRvIE5DRCwgYXMgd2VsbCBhcyBkaXNhYmlsaXR5LWFkanVzdGVkIGxpZmUteWVhcnMgKERBTFlzKSBhdHRyaWJ1dGFibGUgdG8gc3ViLW9wdGltYWwgY29uc3VtcHRpb24gb2YgZm9vZHMgcmVsYXRlZCB0byB0aGVzZSBkaWV0YXJ5IHJpc2sgZmFjdG9ycy4gVGhlIGF1dGhvcnMgZm91bmQgdGhhdDogCgo+ICJIaWdoIGludGFrZSBvZiBzb2RpdW0gLi4uLCBsb3cgaW50YWtlIG9mIHdob2xlIGdyYWlucyAuLi4sIGFuZCBsb3cgaW50YWtlIG9mIGZydWl0cyAuLi4gd2VyZSB0aGUgbGVhZGluZyBkaWV0YXJ5IHJpc2sgZmFjdG9ycyBmb3IgZGVhdGhzIGFuZCBEQUxZcyBnbG9iYWxseSBhbmQgaW4gbWFueSBjb3VudHJpZXMuIiAKClRoaXMgZmlndXJlIGZyb20gdGhlIHBhcGVyJ3Mgc3VwcGxlbWVudGFyeSBtYXRlcmlhbHMgc2hvd3MgdGhlIHJhbmtpbmcgb2YgdGhlIDE1IGRpZXRhcnkgcmlzayBmYWN0b3JzIGJhc2VkIG9uIHRoZSBlc3RpbWF0ZWQgbnVtYmVyIG9mIGF0dHJpYnV0YWJsZSBkZWF0aHMgYW5kIGlsbHVzdHJhdGVzIGhvdyB0aGUgdG9wIDMgcmlzayBmYWN0b3JzIGFyZSBvZnRlbiBpc3N1ZXMgZm9yIG1hbnkgZGlmZmVyZW50IHJlZ2lvbnMgb2YgdGhlIHdvcmxkLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSAiNzAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImRlYXRocy5wbmciKSkKYGBgCgpUaGlzIGNhc2Ugc3R1ZHkgd2lsbCBldmFsdWF0ZSB0aGUgZGF0YSByZXBvcnRlZCBpbiB0aGlzIGFydGljbGUgdG8gZXhwbG9yZSByZWdpb25hbCwgYWdlLCBhbmQgZ2VuZGVyIHNwZWNpZmljIGRpZmZlcmVuY2VzIGluIGRpZXRhcnkgY29uc3VtcHRpb24gcGF0dGVybnMgYXJvdW5kIHRoZSB3b3JsZCBpbiAyMDE3LiAKCiMjICoqTWFpbiBRdWVzdGlvbnMqKgoqKioKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb25zIGFyZTogPC91PjwvYj4KCjEpIFdoYXQgYXJlIHRoZSBnbG9iYWwgdHJlbmRzIGZvciBwb3RlbnRpYWxseSBoYXJtZnVsIGRpZXRzPwoyKSBIb3cgZG8gbWFsZXMgYW5kIGZlbWFsZXMgY29tcGFyZT8KMykgSG93IGRvIGRpZmZlcmVudCBhZ2UgZ3JvdXBzIGNvbXBhcmUgZm9yIHRoZXNlIGRpZXRhcnkgZmFjdG9ycz8KNCkgSG93IGRvIGRpZmZlcmVudCBjb3VudHJpZXMgY29tcGFyZT8gSW4gcGFydGljdWxhciwgaG93IGRvZXMgdGhlIFVTIGNvbXBhcmUgdG8gb3RoZXIgY291bnRyaWVzIGluIHRlcm1zIG9mIGRpZXQgdHJlbmRzPwoKIyMjIwoKIyMgKipMZWFybmluZyBPYmplY3RpdmVzKioKKioqCgpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgd2FsayB5b3UgdGhyb3VnaCBpbXBvcnRpbmcgZGF0YSBmcm9tIFBERiBmaWxlcyBhbmQgQ1NWIGZpbGVzLCBjbGVhbmluZyBkYXRhLCB3cmFuZ2xpbmcgZGF0YSwgY29tcGFyaW5nIGRhdGEsIGpvaW5pbmcgZGF0YSwgdmlzdWFsaXppbmcgZGF0YSwgYW5kIDxiPiBjb21wYXJpbmcgdHdvIG9yIG1vcmUgZ3JvdXBzIDwvYj4gdXNpbmcgd2VsbC1lc3RhYmxpc2hlZCBhbmQgY29tbW9ubHkgdXNlZCBwYWNrYWdlcywgaW5jbHVkaW5nIGBzdHJpbmdyYCwgYHRpZHlyYCwgYGRwbHlyYCwgYHB1cnJyYCwgYW5kIGBnZ3Bsb3QyYC4gV2Ugd2lsbCBlc3BlY2lhbGx5IGZvY3VzIG9uIHVzaW5nIHBhY2thZ2VzIGFuZCBmdW5jdGlvbnMgZnJvbSB0aGUgW1RpZHl2ZXJzZV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0uIFRoZSB0aWR5dmVyc2UgaXMgYSBsaWJyYXJ5IG9mIHBhY2thZ2VzIGNyZWF0ZWQgYnkgUlN0dWRpby4gV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIGVzcGVjaWFsbHkgbGVnaWJsZSBhbmQgaW50dWl0aXZlLgoKVGhlIHNraWxscywgbWV0aG9kcywgYW5kIGNvbmNlcHRzIHRoYXQgc3R1ZGVudHMgd2lsbCBiZSBmYW1pbGlhciB3aXRoIGJ5IHRoZSBlbmQgb2YgdGhpcyBjYXNlIHN0dWR5IGFyZToKCjx1PioqRGF0YSBTY2llbmNlIExlYXJuaW5nIE9iamVjdGl2ZXM6Kio8L3U+CgoxLiBJbXBvcnRpbmcvZXh0cmFjdGluZyBkYXRhIGZyb20gUERGIChgZHBseXJgLCBgc3RyaW5ncmApICAKMi4gSG93IHRvIHJlc2hhcGUgZGF0YSBieSBwaXZvdGluZyBiZXR3ZWVuICJsb25nIiBhbmQgIndpZGUiIGZvcm1hdHMgKGB0aWR5cmApICAgIAozLiBQZXJmb3JtIGZ1bmN0aW9ucyBvbiBhbGwgY29sdW1ucyBvZiBhIHRpYmJsZSAoYHB1cnJyYCkgIAo0LiBEYXRhIGNsZWFuaW5nIHdpdGggcmVndWxhciBleHByZXNzaW9ucyAoYHN0cmluZ3JgKSAgCjUuIFNwZWNpZmljIGRhdGEgdmFsdWUgcmVhc3NpZ25tZW50ICAKNi4gU2VwYXJhdGUgZGF0YSB3aXRoaW4gYSBjb2x1bW4gaW50byBtdWx0aXBsZSBjb2x1bW5zIChgdGlkeXJgKSAKNy4gTWV0aG9kcyB0byBDb21wYXJlIGRhdGEgKGBkcGx5cmApICAKOC4gQ29tYmluaW5nIGRhdGEgZnJvbSB0d28gc291cmNlcyAoYGRwbHlyYCkgIAo5LiBNYWtlIGludGVyYWN0aXZlIHBsb3RzIChgZ2dpcmFwaGApICAKMTAuIE1ha2UgYSB6b29tIGZhY2V0IGZvciBwbG90IChgZ2dmb3JjZWApIAoxMS4gQ29tYmluZSBwbG90cyB0b2dldGhlciAoYGNvd3Bsb3RgKQoKPHU+KipTdGF0aXN0aWNhbCBMZWFybmluZyBPYmplY3RpdmVzOioqPC91PiAKCjEuICBVbmRlcnN0YW5kaW5nIG9mIGhvdyB0aGUgKnQqLXRlc3QgYW5kIHRoZSBBTk9WQSBhcmUgc3BlY2lhbGl6ZWQKICAgIHJlZ3Jlc3Npb25zCjIuICBCYXNpYyB1bmRlcnN0YW5kaW5nIG9mIHRoZSB1dGlsaXR5IG9mIGEgcmVncmVzc2lvbiBhbmFseXNpcwozLiAgSG93IHRvIGltcGxlbWVudCBhIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzIGluIFIKNC4gIEhvdyB0byBpbnRlcnByZXQgcmVncmVzc2lvbiBjb2VmZmljaWVudHMKNS4gIEF3YXJlbmVzcyBvZiAqdCotdGVzdCBhc3N1bXB0aW9ucwo2LiAgQXdhcmVuZXNzIG9mIGxpbmVhciByZWdyZXNzaW9uIGFzc3VtcHRpb25zCjcuICBIb3cgdG8gdXNlIFEtUSBwbG90cyB0byBjaGVjayBmb3Igbm9ybWFsaXR5CjguICBEaWZmZXJlbmNlIGJldHdlZW4gZml4ZWQgZWZmZWN0cyBhbmQgcmFuZG9tIGVmZmVjdHMKOS4gIEhvdyB0byBwZXJmb3JtIHBhaXJlZCAqdCotdGVzdAoxMC4gSG93IHRvIHBlcmZvcm0gYSBsaW5lYXIgbWl4ZWQgZWZmZWN0cyByZWdyZXNzaW9uCgoKYGBge3IsIG91dC53aWR0aCA9ICIyMCUiLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3RpZHl2ZXJzZS50aWR5dmVyc2Uub3JnL2xvZ28ucG5nIikKYGBgCgoqKioKCldlIHdpbGwgYmVnaW4gYnkgbG9hZGluZyB0aGUgcGFja2FnZXMgdGhhdCB3ZSB3aWxsIG5lZWQ6CgpgYGB7cn0KbGlicmFyeShoZXJlKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNraW1yKQpsaWJyYXJ5KHBkZnRvb2xzKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkobG1lNCkKbGlicmFyeShsbWVyVGVzdCkKbGlicmFyeShjYXIpCmxpYnJhcnkoZ2dpcmFwaCkKbGlicmFyeShnZ2ZvcmNlKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkoY293cGxvdCkKYGBgCgoKIFBhY2thZ2UgICB8IFVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbcmVhZHJdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGltcG9ydCB0aGUgQ1NWIGZpbGUgZGF0YQpbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGFycmFuZ2UvZmlsdGVyL3NlbGVjdC9jb21wYXJlIHNwZWNpZmljIHN1YnNldHMgb2YgdGhlIGRhdGEgCltza2ltcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NraW1yL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGdldCBhbiBvdmVydmlldyBvZiBkYXRhCltwZGZ0b29sc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BkZnRvb2xzL3BkZnRvb2xzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgIHwgdG8gcmVhZCBhIFBERiBpbnRvIFIgCltzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9zdHJpbmdyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYW5pcHVsYXRlIHRoZSB0ZXh0IHdpdGhpbiB0aGUgUERGIG9mIHRoZSBkYXRhClttYWdyaXR0cl0oaHR0cHM6Ly9tYWdyaXR0ci50aWR5dmVyc2Uub3JnL2FydGljbGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIHVzZSB0aGUgYCU8PiVgIHBpcGluZyBvcGVyYXRvcgpbcHVycnJdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHBlcmZvcm0gZnVuY3Rpb25zIG9uIGFsbCBjb2x1bW5zIG9mIGEgdGliYmxlClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICB8IHRvIGNyZWF0ZSBkYXRhIG9iamVjdHMgdGhhdCB3ZSBjYW4gbWFuaXB1bGF0ZSB3aXRoIGRwbHlyL3N0cmluZ3IvdGlkeXIvcHVycnIKW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBzZXBhcmF0ZSBkYXRhIHdpdGhpbiBhIGNvbHVtbiBpbnRvIG11bHRpcGxlIGNvbHVtbnMKW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIG1ha2UgdmlzdWFsaXphdGlvbnMgd2l0aCBtdWx0aXBsZSBsYXllcnMKW2dncHVicl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dncHVici9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gZWFzaWx5IGFkZCByZWdyZXNzaW9uIGxpbmUgZXF1YXRpb25zIHRvIHBsb3RzCltmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBjaGFuZ2UgZGV0YWlscyBhYm91dCBmYWN0b3JzIChjYXRlZ29yaWNhbCB2YXJpYWJsZXMpCltsbWU0XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbG1lNC9sbWU0LnBkZil8IHRvIGZpdCBhIGxpbmVhciBtaXhlZCBlZmZlY3RzIG1vZGVsCltsbWVyVGVzdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2xtZXJUZXN0L2xtZXJUZXN0LnBkZil8IHRvIHBlcmZvcm0gbGluZWFyIG1peGVkIG1vZGVsIHRlc3RpbmcKW2Nhcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Nhci9jYXIucGRmKXwgdG8gcGVyZm9ybSBMZXZlbmUncyBUZXN0IG9mIEhvbW9nZW5laXR5IG9mIFZhcmlhbmNlcwpbZ2dpcmFwaF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dnaXJhcGgvaW5kZXguaHRtbCl8IHRvIG1ha2UgcGxvdHMgaW50ZXJhY3RpdmUKW2dnZm9yY2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ2ZvcmNlL2dnZm9yY2UucGRmKXwgdG8gbW9kaWZ5IGZhY2V0cyBpbiBwbG90cwpbdmlyaWRpc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3ZpcmlkaXMvdmlnbmV0dGVzL2ludHJvLXRvLXZpcmlkaXMuaHRtbCl8IHRvIHBsb3QgaW4gYSBjb2xvciBwYWxldHRlIHRoYXQgaXMgZWFzaWx5IGludGVycHJldGVkIGJ5IGNvbG9yYmxpbmQgaW5kaXZpZHVhbHMKW2Nvd3Bsb3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jb3dwbG90L3ZpZ25ldHRlcy9pbnRyb2R1Y3Rpb24uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGFsbG93IHBsb3RzIHRvIGJlIGNvbWJpbmVkCl9fXwoKCgpUaGUgZmlyc3QgdGltZSB3ZSB1c2UgYSBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgdGhlIGA6OmAgdG8gaW5kaWNhdGUgd2hpY2ggcGFja2FnZSB3ZSBhcmUgdXNpbmcuIFVubGVzcyB3ZSBoYXZlIG92ZXJsYXBwaW5nIGZ1bmN0aW9uIG5hbWVzLCB0aGlzIGlzIG5vdCBuZWNlc3NhcnksIGJ1dCB3ZSB3aWxsIGluY2x1ZGUgaXQgaGVyZSB0byBiZSBpbmZvcm1hdGl2ZSBhYm91dCB3aGVyZSB0aGUgZnVuY3Rpb25zIHdlIHdpbGwgdXNlIGNvbWUgZnJvbS4KCgojIyAqKkNvbnRleHQqKgoqKioKCkhlcmUgaXMgYW4gZXhjZXJwdCBmcm9tIHRoZSBhcnRpY2xlIGl0c2VsZiBhYm91dCB0aGUgY29udGV4dCBvZiB0aGUgd29yazoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImNvbnRleHQucG5nIikpCmBgYAoKTWFueSBkaWV0YXJ5IGZhY3RvcnMgaGF2ZSB3ZWxsLWVzdGFibGlzaGVkIGFzc29jaWF0aW9ucyB3aXRoIGhlYWx0aCByaXNrLiBUaGUgYXV0aG9ycyB0aGF0IGdlbmVyYXRlZCB0aGlzIGRhdGEgc2V0IGlkZW50aWZpZWQgMTUgZGlldGFyeSBmYWN0b3JzIHRoYXQgaGF2ZSBwcm9iYWJsZSBoZWFsdGggcmlzayBiYXNlZCBvbiBsaXRlcmF0dXJlIHNlYXJjaC4KCkhlcmUgeW91IGNhbiBzZWUgYSB0YWJsZSBvZiB0aGUgc291cmNlcyBmb3IgdGhlIGhlYWx0aCByaXNrcyBhc3NvY2lhdGVkIHdpdGggdGhlIGRpZXRhcnkgZmFjdG9ycy4gUkNUIHN0YW5kcyBmb3IgcmFuZG9taXplZCBjb250cm9sIHRyaWFscy4KCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiZGlldGFyeXJpc2sucG5nIikpCmBgYAoKCkluIHRoZSBhcnRpY2xlIHRoZSBhdXRob3JzIGZvdW5kIHRoYXQgbW9zdCBvZiB0aGUgbW9ydGFsaXR5IGFzc29jaWF0ZWQgd2l0aCBlYWNoIGZhY3RvciBpcyByZWxhdGVkIHRvIGNhcmRpb3Zhc2N1bGFyIGRpc2Vhc2UuCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9ICI1MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiY2FyZGlvcmlzay5wbmciKSkKYGBgCgojIyAqKkxpbWl0YXRpb25zKioKKioqCgpUaGVyZSBhcmUgc29tZSBpbXBvcnRhbnQgbGltaXRhdGlvbnMgcmVnYXJkaW5nIHRoZSBkYXRhIGZyb20gdGhpcyBhcnRpY2xlIHRvIGtlZXAgaW4gbWluZC4gVGhlIGRlZmluaXRpb24gb2YgY2VydGFpbiBkaWV0YXJ5IGZhY3RvcnMgdmFyaWVkIGFjcm9zcyBzb21lIG9mIHRoZSBjb2xsZWN0aW9uIHNvdXJjZXMuIEludGFrZXMgb2YgY2VydGFpbiBoZWFsdGh5IGZvb2RzIGxpa2UgdmVnZXRhYmxlcyBhbmQgZnJ1aXRzIGFyZSBsaWtlbHkgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlciBhbmQgbGlrZWx5IG5lZ2F0aXZlbHkgY29ycmVsYXRlZCB3aXRoIGludGFrZXMgb2YgdW5oZWFsdGh5IGZvb2RzLiBNdWNoIG9mIHRoZSBkYXRhIHdhcyBjb2xsZWN0ZWQgd2l0aCAyNCBob3VyIHJlY2FsbCBzdXJ2ZXlzIHdoaWNoIGFyZSBwcm9uZSB0byBpc3N1ZXMgZHVlIHRvIGluYWNjdXJhY3kgb2YgbWVtb3J5IHJlY2FsbCBvciBvdGhlciBiaWFzZXMgc3VjaCBhcyBhIHRlbmRlbmN5IGZvciBzb21lIHBlb3BsZSB0byByZXBvcnQgaGVhbHRoaWVyIGJlaGF2aW9ycy4gVGhlIGd1aWRlbGluZXMgaW4gdGhlIFBERiBhcmUgbm90IHNwZWNpZmllZCBieSBnZW5kZXIgZXZlbiB0aG91Z2ggaXQgaXMga25vd24gdGhhdCB0aGVyZSBhcmUgZGlmZmVyZW50IGRpZXRhcnkgcmVxdWlyZW1lbnRzIGZvciBvcHRpbWFsIGhlYWx0aCBmb3IgY2VydGFpbiBudXRyaWVudHMgYnkgZ2VuZGVyLiBUaGUgYXJ0aWNsZSBkaXNjdXNzZXMgc29tZSBsaW1pdGF0aW9ucyBhYm91dCBhY2NvdW50aW5nIGZvciBvdmVyYWxsIGZvb2QgY29uc3VtcHRpb24gd2hlbiBjYWxjdWxhdGluZyBjb25zdW1wdGlvbiBvZiBwYXJ0aWN1bGFyIGZvb2RzOgoKPiAiVG8gcmVtb3ZlIHRoZSBlZmZlY3Qgb2YgZW5lcmd5IGludGFrZSBhcyBhIHBvdGVudGlhbCBjb25mb3VuZGVyIGFuZCBhZGRyZXNzIG1lYXN1cmVtZW50IGVycm9yIGluIGRpZXRhcnkgYXNzZXNzbWVudCB0b29scywgbW9zdCBjb2hvcnRzIGhhdmUgYWRqdXN0ZWQgZm9yIHRvdGFsIGVuZXJneSBpbnRha2UgaW4gdGhlaXIgc3RhdGlzdGljYWwgbW9kZWxzLiBUaGlzIGVuZXJneSBhZGp1c3RtZW50IG1lYW5zIHRoYXQgZGlldCBjb21wb25lbnRzIGFyZSBkZWZpbmVkIGFzIHJpc2tzIGluIHRlcm1zIG9mIHRoZSBzaGFyZSBvZiBkaWV0IGFuZCBub3QgYXMgYWJzb2x1dGUgbGV2ZWxzIG9mIGV4cG9zdXJlLiBJbiBvdGhlciB3b3JkcywgYW4gaW5jcmVhc2UgaW4gaW50YWtlIG9mIGZvb2RzIGFuZCBtYWNyb251dHJpZW50cyBzaG91bGQgYmUgY29tcGVuc2F0ZWQgYnkgYSBkZWNyZWFzZSBpbiBpbnRha2Ugb2Ygb3RoZXIgZGlldGFyeSBmYWN0b3JzIHRvIGhvbGQgdG90YWwgZW5lcmd5IGludGFrZSBjb25zdGFudC4gVGh1cywgdGhlIHJlbGF0aXZlIHJpc2sgb2YgY2hhbmdlIGluIGVhY2ggY29tcG9uZW50IG9mIGRpZXQgZGVwZW5kcyBvbiB0aGUgb3RoZXIgY29tcG9uZW50cyBmb3Igd2hpY2ggaXQgaXMgc3Vic3RpdHV0ZWQuIEhvd2V2ZXIsIHRoZSByZWxhdGl2ZSByaXNrcyBlc3RpbWF0ZWQgZnJvbSBtZXRhLWFuYWx5c2VzIG9mIGNvaG9ydCBzdHVkaWVzIGRvIG5vdCBnZW5lcmFsbHkgc3BlY2lmeSB0aGUgdHlwZSBvZiBzdWJzdGl0dXRpb24uCgpUaGVyZSBhcmUgYWxzbyBpbXBvcnRhbnQgbnVhbmNlcyB0byBrZWVwIGluIG1pbmQgcmVnYXJkaW5nIHNvbWUgb2YgdGhlIGRpZXRhcnkgZmFjdG9ycy4gRm9yIGV4YW1wbGUgY2FsY2l1bSBjb25zdW1wdGlvbiB3YXMgY2FsY3VsYXRlZCBiYXNlZCBvbiBjb25zdW1wdGlvbiBvZiBkYWlyeSBwcm9kdWN0cywgd2hpbGUgY2FsY2l1bSBjYW4gYmUgYWNxdWlyZWQgZnJvbSBvdGhlciBzb3VyY2VzIGluY2x1ZGluZyBwbGFudC1iYXNlZCBzb3VyY2VzLiBIb3dldmVyIGluIHRoZXNlIGRhdGEsIHRoZSBpbmZsdWVuY2Ugb2YgcGxhbnQtYmFzZWQgY29uc3VtcHRpb24gb2YgY2FsY2l1bSB3YXMgbm90IGFjY291bnRlZCBmb3IsIG5vciB3YXMgc3VwcGxlbWVudGF0aW9uIHRocm91Z2ggdml0YW1pbiBzb3VyY2VzLiAKCkFsc28sIHdoaWxlIFtnZW5kZXJdKGh0dHBzOi8vd3d3LmdlbmRlcnNwZWN0cnVtLm9yZy9xdWljay1saW5rcy91bmRlcnN0YW5kaW5nLWdlbmRlci8pe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtzZXhdKGh0dHBzOi8vd3d3Lndoby5pbnQvZ2Vub21pY3MvZ2VuZGVyL2VuL2luZGV4MS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGFyZSBub3QgYWN0dWFsbHkgYmluYXJ5LCB0aGUgZGF0YSB1c2VkIGluIHRoaXMgYW5hbHlzaXMgb25seSBjb250YWlucyBpbmZvcm1hdGlvbiBmb3IgZ3JvdXBzIG9mIGluZGl2aWR1YWxzIGRlc2NyaWJlZCBhcyBtYWxlIG9yIGZlbWFsZS4gCgojIyAqKldoYXQgYXJlIHRoZSBkYXRhPyoqCioqKgoKV2Ugd2lsbCBiZSB1c2luZyBkYXRhIHRoYXQgd2UgcmVxdWVzdGVkIGZyb20gdGhlIFtHQkRdKGh0dHA6Ly93d3cuaGVhbHRoZGF0YS5vcmcvZ2JkKXt0YXJnZXQ9Il9ibGFuayJ9IGFib3V0IGRpZXRhcnkgaW50YWtlLCBhcyB3ZWxsIGFzIHRoZSBndWlkZWxpbmUgZGF0YSBhYm91dCBvcHRpbWFsIGNvbnN1bXB0aW9uIGFtb3VudHMgZm9yIGRpZmZlcmVudCBmb29kcyBjb250YWluZWQgd2l0aGluIHRoZSBQREYgb2YgdGhlIGFydGljbGUuIFdlIGhhdmUgdHdvIENTViBmaWxlcywgZGlldGFyeV9yaXNrX2V4cG9zdXJlX2FsbF9hZ2VzXzIwMTcuY3N2IGFuZCBkaWV0YXJ5X3Jpc2tfZXhwb3N1cmVfc2VwX2FnZXNfMjAxNy5jc3YuIFRoZSBmaXJzdCBvbmUgaW5jbHVkZXMgY29uc3VtcHRpb24gbGV2ZWxzIGF0IHRoZSBnbG9iYWwgbGV2ZWwgYW5kIGZvciBkaWZmZXJlbnQgY291bnRyaWVzIGZvciBhbGwgYWdlcyBjb21iaW5lZC4KCkxvb2tpbmcgYXQgdGhlIENTViBmaWxlIGluIGV4Y2VsOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImNzdi5wbmciKSkKYGBgCgpIZXJlIHlvdSBjYW4gc2VlIHRoYXQgdGhlIGRhdGEgY29udGFpbnMgbWVhbiBjb25zdW1wdGlvbiB2YWx1ZXMgZm9yIGJvdGggbWVuIGFuZCB3b21lbiBpbiB2YXJpb3VzIGNvdW50cmllcyBhdCB0aGUgbmF0aW9uYWwgbGV2ZWwgaW4gMjAxNyBmb3IgdmFyaW91cyBmb29kcyB0aGF0IG1heSBiZSBwcm9ibGVtYXRpYyBmb3IgaGVhbHRoLiBUaGUgdW5pdHMgZm9yIHRoZSBmb29kIHZhcmllcy4gU28gZm9yIGV4YW1wbGUsIHRoZSBtZWFuIGNvbHVtbiBpbiByb3cgdGhhdCBzYXlzICJEaWV0IGxvdyBpbiBmaWJlciIgaW5kaWNhdGVzIHRoZSBhdmVyYWdlIGNvbnN1bXB0aW9uIGxldmVsIHBlciBwZXJzb24gaW4gdGhhdCByZWdpb24gYW5kIG9mIHRoYXQgZ2VuZGVyIG9mIGZpYmVyIGluIGdyYW1zIHBlciBkYXkuCgpUaGUgc2Vjb25kIENTViBmaWxlIGhhcyBzaW1pbGFyIGRhdGEsIGJ1dCBjb25zdW1wdGlvbiBsZXZlbHMgZm9yIGRpZmZlcmVudCBhZ2UgZ3JvdXBzIGFyZSBzZXBhcmF0ZWQuCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiYWdlX3NlcDMucG5nIikpCmBgYAoKVGhlIGF1dGhvcnMgb2YgdGhpcyBhcnRpY2xlIG9idGFpbmVkIHRoZSBkYXRhIGZyb20gYSB2YXJpZXR5IG9mIHNvdXJjZXMgaW5jbHVkaW5nIGhvdXNlaG9sZCBidWRnZXQgc3VydmV5cyBhbmQgbnV0cml0aW9uYWwgc3VydmV5cyByZWdhcmRpbmcgMjQgaG91ciByZWNhbGwgb2YgZm9vZCBjb25zdW1wdGlvbiBhbmQgMjQgaG91ciB1cmluYXJ5IHNvZGl1bSBhbmFseXNpcy4gVGhlIGRhdGEgd2FzIGRlcml2ZWQgZnJvbSBzYWxlcyBkYXRhIGZyb20gRXVyb21vbml0b3IsIGRhdGEgZnJvbSB0aGUgVW5pdGVkIE5hdGlvbnMgRm9vZCBhbmQgQWdyaWN1bHR1cmUgT3JnYW5pemF0aW9uIChGQU8pLCBlc3RpbWF0ZXMgYWJvdXQgbmF0aW9uYWwgYXZhaWxhYmlsaXR5IG9mIHNwZWNpZmljIG51dHJpZW50cywgZnJvbSB0aGUgU3VwcGx5IFV0aWxpemF0aW9uIEFjY291bnRzKFNVQSksIGFuZCB0aGUgVW5pdGVkIFN0YXRlcyBEZXBhcnRtZW50IG9mIEFncmljdWx0dXJlJ3MgTmF0aW9uYWwgTnV0cml0aW9uIERhdGFiYXNlLgoKIyMgKipEYXRhIEltcG9ydCoqCioqKgoKTGV0J3MgaW1wb3J0IG91ciBkYXRhIGludG8gUiBub3cgc28gdGhhdCB3ZSBjYW4gZXhwbG9yZSB0aGUgZGF0YSBmdXJ0aGVyLgoKYGBge3J9CmRpZXRfZGF0YSA8LSByZWFkcjo6cmVhZF9jc3YoaGVyZSgiZG9jcyIsIAogICAgICAgICAgICAgICAgICAgICAgICJkaWV0YXJ5X3Jpc2tfZXhwb3N1cmVfYWxsX2FnZXNfMjAxNy5jc3YiKSkKc2VwX2FnZV9kaWV0X2RhdGEgPC0gcmVhZF9jc3YoaGVyZSgiZG9jcyIsIAogICAgICAgICAgICAgICAgICAgICAgICJkaWV0YXJ5X3Jpc2tfZXhwb3N1cmVfc2VwX2FnZXNfMjAxNy5jc3YiKSkKYGBgCgoKRmlyc3QgbGV0J3MganVzdCBnZXQgYSBnZW5lcmFsIHNlbnNlIG9mIG91ciBkYXRhLiBXZSBjYW4gZG8gdGhhdCB1c2luZyB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSAoaXQgaXMgYWxzbyBpbiB0aGUgYHRpYmJsZWAgcGFja2FnZSkuCgpgYGB7cn0KZHBseXI6OmdsaW1wc2UoZGlldF9kYXRhKQpgYGAKCmBgYHtyfQpnbGltcHNlKHNlcF9hZ2VfZGlldF9kYXRhKQpgYGAKCkhlcmUgd2UgY2FuIHRlbGwgdGhhdCB0aGUgYHNlcF9hZ2VfZGlldF9kYXRhYCBpcyBtdWNoIGxhcmdlciB0aGFuIHRoZSBgZGlldF9kYXRhYC4gVGhlIGBkaWV0X2RhdGFgIGhhcyBvbmx5IDUsODgwIHJvd3Mgd2hpbGUgdGhlIGBzZXBfYWdlX2RpZXRfZGF0YWAgaGFzIDg4LDIwMCByb3dzIQoKSG93ZXZlciwgYm90aCBmaWxlcyBhcHBlYXIgdG8gaGF2ZSB0aGUgc2FtZSBjb2x1bW4gc3RydWN0dXJlIHdpdGggMTEgdmFyaWFibGVzIGVhY2guCgoKVGhlIGBza2ltKClgIGZ1bmN0aW9uIG9mIHRoZSBgc2tpbXJgIHBhY2thZ2UgaXMgYWxzbyByZWFsbHkgaGVscGZ1bCBmb3IgZ2V0dGluZyBhIGdlbmVyYWwgc2Vuc2Ugb2YgeW91ciBkYXRhLgoKYGBge3J9CnNraW0oZGlldF9kYXRhKQpgYGAKCiAgICAgICAgIApOb3RpY2UgaG93IHRoZXJlIGlzIGEgY29sdW1uIHByb3ZpZGluZyB0aGUgbnVtYmVyIG9mIG1pc3Npbmcgb2JzZXJ2YXRpb25zIGZvciBlYWNoIHZhcmlhYmxlLiBJdCBsb29rcyBsaWtlIG91ciBkYXRhIGlzIHZlcnkgY29tcGxldGUgYW5kIHdlIGRvIG5vdCBoYXZlIGFueSBtaXNzaW5nIGRhdGEuCldlIGFsc28gZ2V0IGEgc2Vuc2UgYWJvdXQgdGhlIHNpemUgb2Ygb3VyIGRhdGEuCgpUaGUgYG5fdW5xaXVlYCBjb2x1bW4gc2hvd3MgdXMgdGhlIG51bWJlciBvZiB1bmlxdWUgdmFsdWVzIGZvciBlYWNoIG9mIG91ciBjb2x1bW5zLgoKCkxldCdzIHRha2UgYSBsb29rIGF0IGBzZXBfYWdlX2RpZXRfZGF0YWAuCgpgYGB7cn0Kc2tpbShzZXBfYWdlX2RpZXRfZGF0YSkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIG1hbnkgbW9yZSByb3dzIGluIHRoaXMgZGF0YSBzZXQuCgoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGRpZmZlcmVudCBkaWV0YXJ5IHJpc2sgZmFjdG9ycyBjb25zaWRlcmVkLgpUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgZGlzdGluY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KClRoaXMgZnVuY3Rpb24gZ3JhYnMgb25seSB0aGUgZGlzdGluY3Qgb3IgdW5pcXVlIHJvd3MgZnJvbSBhIGdpdmVuIHZhcmlhYmxlIChgcmVpX25hbWVgLCBpbiBvdXIgY2FzZSkgb2YgYSBnaXZlbiBkYXRhIGZyYW1lIChgZGlldF9kYXRhYCwgaW4gb3VyIGNhc2UpLgoKYGBge3J9CiNkaXN0aW5jdCh0aWJibGVfbmFtZSwgY29sdW1uX25hbWUpCiAgZHBseXI6OmRpc3RpbmN0KGRpZXRfZGF0YSwgcmVpX25hbWUpCmBgYAoKV2Ugd2lsbCBiZSB1c2luZyB0aGUgYCU+JWAgcGlwZSBmb3Igc2VxdWVudGlhbCBzdGVwcyBpbiBvdXIgY29kZSBsYXRlciBvbi4KVGhpcyB3aWxsIG1ha2UgbW9yZSBzZW5zZSB3aGVuIHdlIGhhdmUgbXVsdGlwbGUgc2VxdWVudGlhbCBzdGVwcyB1c2luZyB0aGUgc2FtZSBkYXRhIG9iamVjdC4KCgpXZSBjb3VsZCBkbyB0aGUgc2FtZSBjb2RlIGFzIGFib3ZlIHVzaW5nIHRoaXMgbm90YXRpb24uIEZvciBleGFtcGxlIHdlIGZpcnN0IGdyYWIgdGhlIGBkaWV0X2RhdGFgLCB0aGVuIHdlIHNlbGVjdCB0aGUgZGlzdGluY3QgdmFsdWVzIG9mIHRoZSBgcmVpX25hbWVgIHZhcmlhYmxlLgoKYGBge3J9CmRpZXRfZGF0YSAlPiUKICBkaXN0aW5jdChyZWlfbmFtZSkKYGBgCgpPSywgc28gdGhhdCBnaXZlcyB1cyBhbiBpZGVhIG9mIHdoYXQgZGlldGFyeSBmYWN0b3JzIHdlIGNhbiBleHBsb3JlLCBhbmQgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSAxNSBvZiB0aGVtLiAKCkxldCdzIHNlZSBpZiB0aGUgYGxvY2F0aW9uX25hbWVgIHZhbHVlcyBhcmUgdGhlIHNhbWUgYmV0d2VlbiBib3RoIENTViBmaWxlcy4gVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYHNldGVxdWFsKClgIGZ1bmN0aW9uIG9mIGBkcGx5cmAuCmBgYHtyfQpkcGx5cjo6c2V0ZXF1YWwoCiAgZGlzdGluY3QoZGlldF9kYXRhLCBsb2NhdGlvbl9uYW1lKSwgCiAgZGlzdGluY3Qoc2VwX2FnZV9kaWV0X2RhdGEsIGxvY2F0aW9uX25hbWUpKSAKYGBgCgpPSywgd2UgZ290IHRoZSB2YWx1ZSBvZiBUUlVFLCBzbyBpdCBsb29rcyBsaWtlIHRoZSBzYW1lIGxvY2F0aW9ucyBhcmUgaW4gYm90aCBmaWxlcy4KCk5vdGU6IEluIHRoaXMgY2FzZSB3ZXJlIGNvbXBhcmluZyB0d28gZGlmZmVyZW50IG9iamVjdHMgc28gdXNpbmcgdGhlIHBpcGUgaXMgbm90IGFzIHVzZWZ1bC4KCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBsb2NhdGlvbnMgaW5jbHVkZWQgaW4gdGhlIGRhdGEuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQojc2Nyb2xsIHRocm91Z2ggdGhlIG91dHB1dCEKc2VwX2FnZV9kaWV0X2RhdGEgJT4lCiBkaXN0aW5jdChsb2NhdGlvbl9uYW1lKSAlPiUKICBwdWxsKCkKYGBgCiMjIyMKCgpPSywgc28gdGhlcmUgYXJlIGdsb2JhbCB2YWx1ZXMsIGFzIHdlbGwgYXMgdmFsdWVzIGZvciAxOTUgY291bnRyaWVzLgoKCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBkYXRhIHdoZW4gd2Ugb3JkZXIgaXQgYnkgdGhlIG1lYW4gY29uc3VtcHRpb24gcmF0ZSBjb2x1bW4uIFdlIGNhbiBkbyBzbyB1c2luZyB0aGUgYGFycmFuZ2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KCmBgYHtyfQpkaWV0X2RhdGEgJT4lCiAgZHBseXI6OmFycmFuZ2UobWVhbikgJT4lCiAgZ2xpbXBzZSgpCmBgYAoKT0ssIHNvIGl0IGxvb2tzIGxpa2UgcGVvcGxlIGluIExlYmFub24gZG9uJ3QgZWF0IHZlcnkgbWFueSB0cmFucyBmYXR0eSBhY2lkcy4KCkxldCdzIGFsc28gZmlndXJlIG91dCBob3cgbWFueSB2YWx1ZXMgdGhlcmUgYXJlIGluIGVhY2ggYWdlIGdyb3VwIG9mIHRoZSBkYXRhIHRoYXQgaXMgc2VwYXJhdGVkIGJ5IGFnZS4gV2Ugd2lsbCB1c2UgdGhlIGBjb3VudCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGRvIHRoaXMuCgpgYGB7cn0Kc2VwX2FnZV9kaWV0X2RhdGEgJT4lCmRwbHlyOjpjb3VudChhZ2VfZ3JvdXBfbmFtZSkKYGBgClRoYXQncyBhIGxvdCBvZiB2YWx1ZXMhCgpMZXQncyBsb29rIGEgYml0IGRlZXBlciB0byB0cnkgdG8gdW5kZXJzdGFuZCB3aHkuCldlIGNhbiB1c2UgdGhlIGBjb3VudCgpYCBmdW5jdGlvbiBhZ2FpbiBidXQgZ2V0IHRoZSBudW1iZXIgb2YgdmFsdWVzIGZvciBlYWNoIGNhdGVnb3J5IHdpdGhpbiBgc2V4YCwgYGFnZV9ncm91cF9uYW1lYCBhbmQgYGxvY2F0aW9uX25hbWVgIG9mIHRoZSBkYXRhLgoKYGBge3J9CnNlcF9hZ2VfZGlldF9kYXRhICU+JQogIGNvdW50KHNleCwgYWdlX2dyb3VwX25hbWUsIGxvY2F0aW9uX25hbWUpCmBgYAoKT0ssIHNvIGl0IGxvb2tzIGxpa2UgdGhlc2UgYXJlIHByb2JhYmx5IHRoZSBjb25zdW1wdGlvbiB2YWx1ZXMgZm9yIGVhY2ggb2YgdGhlIGRpZmZlcmVudCBkaWV0YXJ5IGZhY3RvcnMgKHNpbmNlIHRoZXJlIHdlcmUgMTUgZGlmZmVyZW50IGZhY3RvcnMpIGZvciBlYWNoIGFnZSBncm91cCBhbmQgZ2VuZGVyIGNvbWJpbmF0aW9uIHdpdGhpbiBlYWNoIGNvdW50cnkuCgpXZSBjYW4gY29uZmlybSB0aGlzIGJ5IGZpbHRlcmluZyB0aGUgZGF0YSB0byBvbmUgb2YgdGhlIGFnZSBncm91cHMsIGZvciBhIHNpbmdsZSBnZW5kZXIsIGFuZCBmb3IgYSBzaW5nbGUgbG9jYXRpb24uIFRvIGRvIHRoaXMgd2UgY2FuIHVzZSB0aGUgYGZpbHRlcigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBOb3RpY2UgdGhhdCB3ZSBuZWVkIHRvIHVzZSB0d28gZXF1YWwgc2lnbnMgYD09YCB0byBzcGVjaWZ5IHdoYXQgdmFsdWVzIHdlIHdvdWxkIGxpa2UgZm9yIGVhY2ggdmFyaWFibGUuCgpgYGB7cn0Kc2VwX2FnZV9kaWV0X2RhdGEgJT4lCmRwbHlyOjpmaWx0ZXIoc2V4ID09ICJGZW1hbGUiLAogICBhZ2VfZ3JvdXBfbmFtZSA9PSAiMjUgdG8gMjkiLAogICAgbG9jYXRpb25fbmFtZSA9PSAiQWZnaGFuaXN0YW4iKQpgYGAKClRoaXMgY29uZmlybXMgdGhhdCBmb3IgZWFjaCBvZiB0aGUgMTUgZGlldGFyeSBmYWN0b3JzLCBvdXIgdW5pdCBvZiBvYnNlcnZhdGlvbiBpcyBhIGNvbWJpbmF0aW9uIG9mIGdlbmRlciwgYWdlIGFuZCBjb3VudHJ5LiBIb3dldmVyLCBiZWZvcmUgd2UgcHJvY2VlZCB3aXRoIG91ciBhbmFseXNpcywgd2Ugd2lsbCB3YW50IHRvIHBlcmZvcm0gc29tZSBhZGRpdGlvbmFsIGRhdGEgd3JhbmdsaW5nLiBUbyBkbyB0aGlzLCB3ZSB3aWxsIGludHJvZHVjZSB0aGUgYHBkZnRvb2xzYCBwYWNrYWdlLCB3aGljaCB3aWxsIGFsbG93IHVzIHRvIHB1bGwgYWRkaXRpb25hbCBkYXRhIGZyb20gdGhlIG1hbnVzY3JpcHQgaXRzZWxmLgoKCgojIyAqKkRhdGEgV3JhbmdsaW5nKioKKioqCgpXaGlsZSBhbGwgb2YgdGhlIG1lYW4gY29uc3VtcHRpb24gdmFsdWVzIGFyZSByZXBvcnRlZCBpbiBncmFtcywgZWFjaCBkaWV0YXJ5IGZhY3RvciBoYXMgYSBkaWZmZXJlbnQgYW1vdW50IHRoYXQgaXMgY29uc2lkZXJlZCBvcHRpbWFsIGZvciBjb25zdW1pbmcuIFRvIG1ha2UgdGhlIGNvbnN1bXB0aW9uIHZhbHVlcyBtb3JlIGNvbXBhcmFibGUgYWNyb3NzIGZhY3RvcnMsIGxldCdzIGFsc28gZ2V0IHNvbWUgZGF0YSBmcm9tIHRoZSBQREYgb2YgdGhlIHBhcGVyIHNvIHRoYXQgd2UgY2FuIGNhbGN1bGF0ZSBjb25zdW1wdGlvbiBvZiB0aGVzZSBkaWV0YXJ5IGZhY3RvcnMgYXMgcGVyY2VudGFnZXMgb2YgdGhlIGRhaWx5IG9wdGltdW0uCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGlzIHRhYmxlIG9uIHBhZ2UgMzoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJUYWJsZS5wbmciKSkKYGBgCgoKRmlyc3QgbGV0J3MgaW1wb3J0IHRoZSBQREYgdXNpbmcgdGhlIGBwZmRfdGV4dCgpYCBmdW5jdGlvbiBvZiB0aGUgYHBkZnRvb2xzYCBwYWNrYWdlLgpgYGB7cn0KcGFwZXIgPC0gcGRmdG9vbHM6OnBkZl90ZXh0KGhlcmUoImRvY3MiLCAKIkFmc2hpbiBldCBhbC4gMjAxOSAtIEhlYWx0aCBlZmZlY3RzIG9mIGRpZXRhcnkgcmlza3MgaW4gMTk1IGNvdW50cmllcywgIC4uLiAxNyAtIGEgc3lzdGVtYXRpYyBhbmFseXNpcyBmb3IgdGhlIEdsb2JhbCBCdXJkZW4gb2YgRGlzZWFzZSBTdHVkeSAyMDE3LnBkZiIpKQpgYGAKCldlIGNhbiB1c2UgdGhlIGBiYXNlYCBgc3VtbWFyeSgpYCBmdW5jdGlvbiB0byBnZXQgYSBzZW5zZSBvZiB3aGF0IHRoZSBkYXRhIGxvb2tzIGxpa2UuIEJ5IGBiYXNlYCB3ZSBtZWFuIHRoYXQgdGhlc2UgZnVuY3Rpb25zIGFyZSBwYXJ0IG9mIHRoZSBgYmFzZWAgcGFja2FnZSBhbmQgYXJlIGxvYWRlZCBhdXRvbWF0aWNhbGx5IG9uIHN0YXJ0dXAgb2YgUi4gVGh1cyBgbGlicmFyeShiYXNlKWAgaXMgbm90IHJlcXVpcmVkLgpgYGB7cn0KI1RoaXMgaXMgZXF1aXZhbGVudCB0byB0aGUgZm9sbG93aW5nLCBidXQgdGhpcyBpcyB1bmVjZXNzYXJ5OgojYmFzZTo6c3VtbWFyeShwYXBlcikKc3VtbWFyeShwYXBlcikKYGBgCgpXZSBjYW4gc2VlIHRoYXQgd2UgaGF2ZSAxNSBkaWZmZXJlbnQgY2hhcmFjdGVyIHN0cmluZ3MuIEVhY2ggb25lIGNvbnRhaW5zIHRoZSB0ZXh0IG9uIGVhY2ggb2YgdGhlIDE1IGRpZmZlcmVudCBwYWdlcyBvZiB0aGUgUERGLgoKQWdhaW4sIHRoZSB0YWJsZSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBpcyBvbiB0aGUgdGhpcmQgcGFnZSwgc28gbGV0J3MgZ3JhYiBqdXN0IHRoYXQgcG9ydGlvbiBvZiB0aGUgUERGLiBUaGUgdG9wIG9mIHRoaXMgcGFnZSBsb29rcyBsaWtlOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInBhZ2UzLnBuZyIpKQpgYGAKCmBgYHtyfQojSGVyZSB3ZSB3aWxsIHNlbGVjdCB0aGUgM3JkIHZhbHVlIGluIHRoZSBwYXBlciBvYmplY3QKcGRmX3RhYmxlIDwtIHBhcGVyWzNdCgpzdW1tYXJ5KHBkZl90YWJsZSkKCiNzcGVjaWZ5aW5nIG5jaGFyLm1heCB0cnVuY2F0ZXMgdGhlIG91dHB1dApnbGltcHNlKHBkZl90YWJsZSwgbmNoYXIubWF4ID0gODAwKQoKYGBgCgpIZXJlIHdlIGNhbiBzZWUgdGhhdCB0aGUgYHBkZl90YWJsZWAgb2JqZWN0IG5vdyBjb250YWlucyB0aGUgdGV4dCBmcm9tIHRoZSAzcmQgcGFnZSBhcyBhICoqc2luZ2xlIGxhcmdlIGNoYXJhY3RlciBzdHJpbmcqKi4gSG93ZXZlciB0aGUgdGV4dCBpcyBkaWZmaWN1bHQgdG8gcmVhZCBiZWNhdXNlIG9mIHRoZSBjb2x1bW4gc3RydWN0dXJlIGluIHRoZSBQREYuIE5vdyBsZXQncyB0cnkgdG8gZ3JhYiBqdXN0IHRoZSB0ZXh0IGluIHRoZSB0YWJsZS4KCk9uZSB3YXkgdG8gYXBwcm9hY2ggdGhpcyBpcyB0byBzcGxpdCB0aGUgc3RyaW5nIGJ5IHNvbWUgcGF0dGVybiB0aGF0IHdlIG5vdGljZSBpbiB0aGUgdGFibGUuCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiVGFibGUucG5nIikpCmBgYAoKQWxsIHRoZSByb3dzIG9mIGludGVyZXN0IG9mIHRoZSB0YWJsZSBhcHBlYXIgdG8gc3RhcnQgd2l0aCB0aGUgd29yZCBgIkRpZXQiYC4gTW9yZW92ZXIsIG9ubHkgdGhlIGNhcGl0YWxpemVkIGZvcm0gb2YgdGhlIHdvcmQgYCJEaWV0ImAgYXBwZWFycyB0byBiZSB3aXRoaW4gdGhlIHRhYmxlLCBhbmQgaXQgaXMgbm90IHByZXNlbnQgaW4gdGhlIHByZWNlZGluZyB0ZXh0IChhbHRob3VnaCBgImRpZXQiYCBpcykuIAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIkRpZXRfb25fcGFnZTMucG5nIikpCmBgYAoKCkxldCdzIHVzZSB0aGUgYHN0cl9zcGxpdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gc3BsaXQgdGhlIGRhdGEgd2l0aGluIHRoZSBvYmplY3QgY2FsbGVkIGBwZGZfdGFibGVgIGJ5IHRoZSB3b3JkIGAiRGlldCJgLiAgT25seSBsaW5lcyBmcm9tIHBhZ2UgMyB0aGF0IGNvbnRhaW4gdGhlIHdvcmQgYCJEaWV0ImAgd2lsbCBiZSBzZWxlY3RlZCAoYW5kIG5vdCBgImRpZXQiYCBhcyB0aGlzIGZ1bmN0aW9uIGlzIGNhc2Utc2Vuc2l0aXZlKS4gRWFjaCBzZWN0aW9uIG9mIHRoZSB0ZXh0IHRoYXQgY29udGFpbnMgYCJEaWV0ImAgd2lsbCBiZSBzcGxpdCBpbnRvIGluZGl2aWR1YWwgcGllY2VzIGV2ZXJ5IHRpbWUgdGhlIHdvcmQgYCJEaWV0ImAgb2NjdXJzIGFuZCB0aGUgd29yZCBpdHNlbGYgd2lsbCBiZSByZW1vdmVkLgoKSW4gdGhpcyBjYXNlIHdlIGFyZSBhbHNvIHVzaW5nIHRoZSBtYWdyaXR0ciBhc3NpZ25tZW50IHBpcGUgb3IgZG91YmxlIHBpcGUgdGhhdCBsb29rcyBsaWtlIHRoaXMgYCU8PiVgIG9mIHRoZSBgbWFncml0dHJgIHBhY2thZ2UuIFRoaXMgYWxsb3dzIHVzIHVzZSB0aGUgYHBkZl90YWJsZWAgZGF0YSBhcyBpbnB1dCB0byB0aGUgbGF0ZXIgc3RlcHMgYnV0IGFsc28gcmVhc3NpZ24gdGhlIG91dHB1dCB0byB0aGUgc2FtZSBkYXRhIG9iamVjdCBuYW1lLgoKYGBge3J9CnBkZl90YWJsZSAlPD4lCiAgc3RyaW5ncjo6c3RyX3NwbGl0KHBhdHRlcm4gPSAnRGlldCcpCmBgYAoKVXNpbmcgdGhlIGBiYXNlOjpzdW1tYXJ5KClgIGFuZCBgZHBseXI6OmdsaW1wc2UoKWAgZnVuY3Rpb24gd2UgY2FuIHNlZSB0aGF0IHdlIGNyZWF0ZWQgYSBsaXN0IG9mIHRoZSByb3dzIGluIHRoZSB0YWJsZSB0aGF0IGNvbnRhaW5lZCB0aGUgd29yZCBgIkRpZXQiYC4gV2UgY2FuIHNlZSB0aGF0IHdlIHN0YXJ0IHdpdGggdGhlIHJvdyB0aGF0IGNvbnRhaW5zIGAibG93IGluIGZydWl0cyJgLiAKCmBgYHtyfQpwZGZfdGFibGUgJT4lCiBzdW1tYXJ5KCkKYGBgCgpgYGB7cn0KcGRmX3RhYmxlICU+JQogIGdsaW1wc2UoKQpgYGAKSW4gb3JkZXIgdG8gZXh0cmFjdCB0aGUgdmFsdWVzIHRoYXQgd2Ugd2FudCBmcm9tIHRoZXNlIGNoYXJhY3RlciBzdHJpbmdzLCB3ZSB3aWxsIHVzZSBzb21lIGFkZGl0aW9uYWwgZnVuY3Rpb25zIGZyb20gdGhlIGBzdHJpbmdyYCBwYWNrYWdlLiBSU3R1ZGlvIGNyZWF0ZXMgcmVhbGx5IGhlbHBmdWwgY2hlYXQgc2hlZXRzIGxpa2UgdGhpcyBvbmUgd2hpY2ggc2hvd3MgeW91IGFsbCB0aGUgbWFqb3IgZnVuY3Rpb25zIGluIHRoZSBgc3RyaW5ncmAgcGFja2FnZS4gWW91IGNhbiBkb3dubG9hZCBvdGhlcnMgW2hlcmVdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLyl7dGFyZ2V0PSJfYmxhbmsifS4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJzdHJpbmdzLTFfc3RyX3NwbGl0LnBuZyIpKQpgYGAKCllvdSBjYW4gc2VlIHRoYXQgd2UgY291bGQgaGF2ZSBhbHNvIHVzZWQgdGhlIGBzdHJfc3BsaXRfZml4ZWQoKWAgZnVuY3Rpb24gd2hpY2ggd291bGQgYWxzbyBzZXBhcmF0ZSB0aGUgc3Vic3RyaW5ncyBpbnRvIGRpZmZlcmVudCBjb2x1bW5zIG9mIGEgbWF0cml4LCBob3dldmVyIHdlIHdvdWxkIG5lZWQgdG8ga25vdyB0aGUgbnVtYmVyIG9mIHN1YnN0cmluZ3Mgb3IgcGllY2VzIHRoYXQgd2Ugd291bGQgbGlrZSByZXR1cm5lZC4KCkZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGBzdHJfc3BsaXQoKWAgc2VlIFtoZXJlXShodHRwOi8vcmZ1bmN0aW9uLmNvbS9hcmNoaXZlcy8xNDk5KXt0YXJnZXQ9Il9ibGFuayJ9LgoKTGV0J3Mgc2VwYXJhdGUgdGhlIHZhbHVlcyB3aXRoaW4gdGhlIGxpc3QgdXNpbmcgdGhlIGJhc2UgYHVubGlzdGAgZnVuY3Rpb24sIHRoaXMgd2lsbCBhbGxvdyB1cyB0byBlYXNpbHkgc2VsZWN0IHRoZSBkaWZmZXJlbnQgc3Vic3RyaW5ncyB3aXRoaW4gdGhlIG9iamVjdCBjYWxsZWQgYHBkZl90YWJsZWAuCgpgYGB7cn0KcGRmX3RhYmxlICU8PiUKICB1bmxpc3QoKQpgYGAKCkl0J3MgaW1wb3J0YW50IHRvIHJlYWxpemUgdGhhdCB0aGUgZmlyc3Qgc3BsaXQgd2lsbCBzcGxpdCB0aGUgdGV4dCBiZWZvcmUgdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgYCJEaWV0ImAgYXMgdGhlIGZpcnN0IHZhbHVlIGluIHRoZSBvdXRwdXQuIChUaGlzIGlzIHdoeSB0aGVyZSBhcmUgMTcgZWxlbWVudHMgaW4gYHBkZl90YWJsZWAgcmF0aGVyIHRoYW4gMTUsIHRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgdGFibGUuKSBXZSBjb3VsZCB1c2UgdGhlIGBmaXJzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGxvb2sgYXQgdGhpcyB2YWx1ZS4gSG93ZXZlciwgd2Ugd2lsbCBzdXBwcmVzcyB0aGUgb3V0cHV0IGFzIHRoaXMgaXMgcXVpdGUgbGFyZ2UuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkcGx5cjo6Zmlyc3QocGRmX3RhYmxlKQpgYGAKCkluc3RlYWQgd2UgY2FuIHRha2UgYSBsb29rIGF0IHRoZSBzZWNvbmQgZWxlbWVudCBvZiB0aGUgbGlzdC4gdXNpbmcgdGhlIGBudGgoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYC4KCmBgYHtyfQpudGgocGRmX3RhYmxlLCAyKQpgYGAKCkluZGVlZCB0aGlzIGxvb2tzIGxpa2UgdGhlIGZpcnN0IHJvdyBvZiBpbnRlcmVzdCBpbiBvdXIgdGFibGU6CgpgYGB7cixlY2hvID0gRkFMU0Usb3V0LndpZHRoPSAiODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiZmlyc3Ryb3cucG5nIikpCmBgYAoKClVzaW5nIHRoZSBgbGFzdCgpYCBhbmQgdGhlIGBudGgoKWAgZnVuY3Rpb25zIG9mIHRoZSBgZHBseXJgIHBhY2thZ2Ugd2UgY2FuIHRha2UgYSBsb29rIGF0IHRoZSBsYXN0IHZhbHVlcyBvZiB0aGUgbGlzdC4KYGBge3J9CiN0byBzZWUgdGhlIHNlY29uZCB0byBsYXN0IHZhbHVlIHdlIGNhbiB1c2UgbnRoKCkKI3RoZSAtMiBzcGVjaWZpZXMgdGhhdCB3ZSB3YW50IHRoZSBzZWNvbmQtdG8tbGFzdCB2YWx1ZQojLTMgd291bGQgYmUgdGhpcmQtdG8tbGFzdCBhbmQgLTEgd291bGQgYmUgdGhlIGxhc3QgdmFsdWUKZHBseXI6Om50aChwZGZfdGFibGUsIC0yKQoKI3RvIHNlZSB0aGUgdmVyeSBsYXN0IHZhbHVlIHdlIGNhbiB1c2UgbGFzdCgpCmRwbHlyOjpsYXN0KHBkZl90YWJsZSkKCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImVuZF9vZl90YWJsZS5wbmciKSkKYGBgCgoKV2UgZG9uJ3QgbmVlZCB0aGlzIHBhcnQgb2YgdGhlIHRhYmxlIG9yIHRoZSB0ZXh0IGJlZm9yZSB0aGUgdGFibGUgaWYgd2UganVzdCB3YW50IHRoZSBjb25zdW1wdGlvbiByZWNvbW1lbmRhdGlvbnMuIAoKU28gd2Ugd2lsbCBzZWxlY3QgdGhlIHNlY29uZCB0aHJvdWdoIHRoZSBzZWNvbmQtdG8tbGFzdCBvZiB0aGUgc3Vic3RyaW5ncy4gU2luY2Ugd2UgaGF2ZSBzZXZlbnRlZW4gc3Vic3RyaW5ncywgd2Ugd2lsbCBzZWxlY3QgdGhlIHNlY29uZCB0aHJvdWdoIHRoZSBzaXh0ZWVudGguIEhvd2V2ZXIgYSBiZXR0ZXIgd2F5IHRvIGRvIHRoaXMgcmF0aGVyIHRoYW4gc2VsZWN0aW5nIGJ5IGluZGV4LCB3b3VsZCBiZSB0byBzZWxlY3QgcGhyYXNlcyB0aGF0IGFyZSB1bmlxdWUgdG8gdGhlIHRleHQgd2l0aGluIHRoZSB0YWJsZSB0aGF0IHdlIHdhbnQuIFdlIHdpbGwgdXNlIHRoZSBgc3RyX3N1YnNldCgpYCBmdW5jdGlvbiBvZiBgc3RyaW5ncmAgcGFja2FnZSB0byBzZWxlY3QgdGhlIHRhYmxlIHJvd3Mgd2l0aCBjb25zdW1wdGlvbiBndWlkZWxpbmVzLiAgTW9zdCBvZiB0aGUgcm93cyBoYXZlIHRoZSBwaHJhc2UgIk1lYW4gZGFpbHkgY29uc3VtcHRpb24iLCBob3dldmVyLCB0aGVyZSBhcmUgb3RoZXIgcGhyYXNlcyBmb3Igc29tZSBvZiB0aGUgcm93cywgaW5jbHVkaW5nICJNZWFuIGRhaWx5IGludGFrZSIgYW5kICIyNCBoIHNvZGl1bSIuIFNvIHdlIHdpbGwgc3Vic2V0IGZvciBlYWNoIG9mIHRoZXNlIHBocmFzZXMuCgpgYGB7cn0KIyBvbmUgY291bGQgc3Vic2V0IHRoZSBwZGZfdGFibGUgbGlrZSB0aGlzOgojcGRmX3RhYmxlIDwtIHBkZl90YWJsZVsyOjE2XQoKcGRmX3RhYmxlICU8PiUKc3RyX3N1YnNldChwYXR0ZXJuID0gIk1lYW4gZGFpbHkgY29uc3VtcHRpb258TWVhbiBkYWlseSBpbnRha2V8MjQgaCIpCmBgYAoKTm90aWNlIHRoYXQgd2Ugc2VwYXJhdGUgdGhlIGRpZmZlcmVudCBwYXR0ZXJucyB0byBsb29rIGZvciB1c2luZyB2ZXJ0aWNhbCBiYXIgY2hhcmFjdGVyIGAifCJgIGFuZCB0aGF0IGFsbCBvZiB0aGUgcGF0dGVybnMgYXJlIHdpdGhpbiBxdW90YXRpb24gbWFya3MgdG9nZXRoZXIuCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9Cjx1PlF1ZXN0aW9uIG9wcG9ydHVuaXR5OjwvdT4gCgoxKSBXaGF0IG90aGVyIHN0cmluZyBwYXR0ZXJucyBjb3VsZCB5b3UgdXNlIHRvIHN1YnNldCB0aGUgcm93cyBvZiB0aGUgdGFibGUgdGhhdCB3ZSB3YW50PwoKMikgV2h5IG1pZ2h0IGl0IGJlIGJldHRlciB0byBzdWJzZXQgYmFzZWQgb24gdGhlIHRleHQgcmF0aGVyIHRoYW4gdGhlIGluZGV4PwoKIyMjIwoKCk5vdyB0aGUgZmlyc3Qgcm93IGlzIHdoYXQgd2Ugd2FudDoKYGBge3J9CmZpcnN0KHBkZl90YWJsZSkKYGBgCgpBbmQgdGhlIGxhc3Qgcm93IGlzIHdoYXQgd2Ugd2FudDoKYGBge3J9Cmxhc3QocGRmX3RhYmxlKQpgYGAKCkF0IHRoaXMgcG9pbnQsIHdlIGhhdmUgYSBiZXR0ZXIgbG9vayBhdCB0aGUgY3VycmVudCByZXByZXNlbnRhdGlvbiBvZiB0aGUgdGFibGUgZGF0YSBpbiBSLCBhbmQgd2UgbWlnaHQgbm90aWNlIHNvbWV0aGluZyB0aGF0IHdpbGwgbmVlZCB0byBiZSBmaXhlZC4gSW4gdGhlIHN0cmluZyBhYm92ZSwgdGhlIGRlY2ltYWwgcG9pbnRzIGZyb20gdGhlIFBERiBhcmUgYmVpbmcgcmVjb2duaXplZCBhcyBzb21ldGhpbmcgY2FsbGVkIGFuIGludGVycHVuY3QgaW5zdGVhZCBvZiBhIHBlcmlvZCBvciBkZWNpbWFsLiBBbiBpbnRlcnB1bmN0IGlzIGEgY2VudGVyZWQgZG90LCBhcyBvcHBvc2VkIHRvIGEgcGVyaW9kIG9yIGRlY2ltYWwgdGhhdCBpcyBhbGlnbmVkIHRvIHRoZSBib3R0b20gb2YgdGhlIGxpbmUuCgpUaGUgaW50ZXJwdW5jdCB3YXMgcHJldmlvdXNseSB1c2VkIHRvIHNlcGFyYXRlIHdvcmRzIGluIGNlcnRhaW4gbGFuZ3VhZ2VzLCBsaWtlIGFuY2llbnQgTGF0aW4uCgoKPHAgYWxpZ249ImNlbnRlciI+CiAgPGltZyB3aWR0aD0iNDAwIiBzcmM9Imh0dHBzOi8vd3d3LnlvdXJkaWN0aW9uYXJ5LmNvbS9pbWFnZS9hcnRpY2xlcy8zNDE3LkxhdGluLmpwZyI+CjwvcD4KCiMjIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly93d3cueW91cmRpY3Rpb25hcnkuY29tL2ltYWdlL2FydGljbGVzLzM0MTcuTGF0aW4uanBnKV0KCllvdSBjYW4gcHJvZHVjZSBhbiBpbnRlcnB1bmN0IG9uIGEgTWFjIGxpa2UgdGhpczoKCgo8cCBhbGlnbj0iY2VudGVyIj4KICA8aW1nIHdpZHRoPSI0MDAiIHNyYz0iaHR0cHM6Ly93d3cuc2hvcnR0dXRvcmlhbHMuY29tL21hYy1vcy1zcGVjaWFsLWNoYXJhY3RlcnMtc2hvcnRjdXRzL2ltYWdlcy9taWRkbGUtZG90LnBuZyI+CjwvcD4KCiMjIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly93d3cuc2hvcnR0dXRvcmlhbHMuY29tL21hYy1vcy1zcGVjaWFsLWNoYXJhY3RlcnMtc2hvcnRjdXRzL21pZGRsZS1kb3QuaHRtbCldCgoKSXQgaXMgaW1wb3J0YW50IHRvIHJlcGxhY2UgdGhlc2UgZm9yIGxhdGVyIHdoZW4gd2Ugd2FudCB0aGVzZSB2YWx1ZXMgdG8gYmUgY29udmVydGVkIGZyb20gY2hhcmFjdGVyIHN0cmluZ3MgdG8gbnVtZXJpYy4gV2Ugd2lsbCBhZ2FpbiB1c2UgdGhlIGBzdHJpbmdyYCBwYWNrYWdlLiBUaGlzIHRpbWUgd2Ugd2lsbCB1c2UgdGhlIGBzdHJfcmVwbGFjZV9hbGwoKWAgZnVuY3Rpb24gd2hpY2ggcmVwbGFjZXMgYWxsIGluc3RhbmNlcyBvZiBhIHBhdHRlcm4gaW4gYW4gaW5kaXZpZHVhbCBzdHJpbmcuIEluIHRoaXMgY2FzZSB3ZSB3YW50IHRvIHJlcGxhY2UgYWxsIGluc3RhbmNlcyBvZiB0aGUgaW50ZXJwdW5jdCB3aXRoIGEgZGVjaW1hbCBwb2ludC4KCgpgYGB7cix9CnBkZl90YWJsZSAlPD4lCiAgc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKCBwYXR0ZXJuID0gIsK3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIi4iKQpgYGAKCkxvb2tzIGdvb2QhCgpgYGB7cn0KbGFzdChwZGZfdGFibGUpCmBgYAoKTm93IHdlIHdpbGwgdHJ5IHRvIHNwbGl0IHRoZSBzdHJpbmdzIGZvciBlYWNoIHJvdyBiYXNlZCBvbiB0aGUgcHJlc2VuY2Ugb2YgdHdvIHNwYWNlcyB0byBjcmVhdGUgdGhlIGNvbHVtbnMgb2YgdGhlIHRhYmxlLCBhcyB0aGVyZSBhcHBlYXJzIHRvIGJlIG1vcmUgdGhhbiBvbmUgc3BhY2UgYmV0d2VlbiB0aGUgY29sdW1ucy4gVGhlIHJlc3VsdGluZyBzdWJzdHJpbmdzIHdpbGwgYmUgc2VwYXJhdGVkIGJ5IHF1b3Rlcy4KCkZvciBhZGRpdGlvbmFsIGRldGFpbHMsIHRoZSBzZWNvbmQgcGFnZSBvZiB0aGUgYHN0cmluZ3JgIGNoZWF0IHNoZWV0IGhhcyBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHVzaW5nICJTcGVjaWFsIENoYXJhY3RlcnMiIGluIGBzdHJpbmdyYC4gRm9yIGV4YW1wbGUgYFxcc2AgaXMgaW50ZXJwcmV0ZWQgYXMgYSBzcGFjZSBhcyB0aGUgYFxcYCBpbmRpY2F0ZXMgdGhhdCB0aGUgYHNgIHNob3VsZCBiZSBpbnRlcnByZXRlZCBhcyBhIHNwZWNpYWwgY2hhcmFjdGVyIGFuZCBub3Qgc2ltcGx5IHRoZSBsZXR0ZXIgcy4gIFRoZSBgezIsfWAgaW5kaWNhdGVzIHR3byBvciBtb3JlIHNwYWNlcywgd2hpbGUgYHsyfWAgd291bGQgaW5kaWNhdGUgZXhhY3RseSB0d28gc3BhY2VzLgoKYGBge3IsIGVjaG8gPSBGQUxTRSxvdXQud2lkdGggPSAiODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAic3RyaW5ncy0yX2hpZ2hsaWdodC5wbmciKSkKYGBgCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQp0YWJsZV9zcGxpdCA8LSBzdHJfc3BsaXQoc3RyaW5nID0gcGRmX3RhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJcXHN7Mix9IikKZ2xpbXBzZSh0YWJsZV9zcGxpdCkgI3Njcm9sbCB0aGUgb3V0cHV0IQpgYGAKIyMjIwoKTm93IHdlIGNhbiBzZWUgdGhhdCBlYWNoIG9mIG91ciAxNSBzdHJpbmdzIGhhcyBiZWVuIHNwbGl0IGludG8gcGllY2VzLCBidXQgdW5mb3J0dW5hdGVseSwgaXQgd2FzIG5vdCBjb21wbGV0ZWx5IGNvbnNpc3RlbnQgYWNyb3NzIGRpZXRhcnkgZmFjdG9ycy4gV2h5IGRpZCB0aGlzIGhhcHBlbj8gSWYgd2UgbG9vayBjbG9zZWx5LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZSBhbmQgdGhlIHNlYWZvb2QgY2F0ZWdvcnkgaGFkIG9ubHkgb25lIHNwYWNlIGJldHdlZW4gdGhlIGZpcnN0IGFuZCBzZWNvbmQgY29sdW1ucy4gVGhlc2UgYXJlIHRoZSBjb2x1bW5zIGFib3V0IHRoZSBkaWV0YXJ5IGNhdGVnb3J5IGFuZCB0aGUgb25lIHRoYXQgZGVzY3JpYmVzIGluIG1vcmUgZGV0YWlsIHdoYXQgdGhlIGNvbnN1bXB0aW9uIHN1Z2dlc3Rpb24gaXMgYWJvdXQuCgpUaGUgdmFsdWVzIGZvciB0aGVzZSB0d28gY29sdW1ucyBhcHBlYXIgdG8gYmUgdG9nZXRoZXIgc3RpbGwgaW4gdGhlIHNhbWUgc3Vic3RyaW5nIGZvciB0aGVzZSB0d28gY2F0ZWdvcmllcy4gV2UgY2FuIHNlZSB0aGlzIGJlY2F1c2UgdGhlcmUgYXJlIG5vIHF1b3RhdGlvbiBtYXJrcyBhZGphY2VudCB0byB0aGUgd29yZCBgIk1lYW4iYC4KCkhlcmUgeW91IGNhbiBzZWUgaG93IHRoZSBuZXh0IHN1YnN0cmluZyBzaG91bGQgaGF2ZSBzdGFydGVkIHdpdGggdGhlIHdvcmQgYCJNZWFuImAgYnkgdGhlIG5ldyBpbmNsdXNpb24gb2YgYSBxdW90YXRpb24gbWFyayBgImAuIFRoZSByZWQgcmVjdGFuZ2xlcyBpbmRpY2F0ZSB0aGUgcHJvYmxlbWF0aWMgc3Vic3RyaW5ncywgd2hpbGUgdGhlIGdyZWVuIHJlY3RhbmdsZXMgc2hvdyBleGFtcGxlcyB3aGVyZSB0aGUgc3BsaXQgd29ya2VkIGNvcnJlY3RseS4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI3MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJzdWJzdHJpbmdfc2VwLnBuZyIpKQpgYGAKCgpXZSBjYW4gYWRkIGFuIGV4dHJhIHNwYWNlIGluIGZyb250IG9mIHRoZSB3b3JkIGAiTWVhbiJgIGZvciB0aGVzZSBwYXJ0aWN1bGFyIGNhdGVnb3JpZXMgYW5kIHRoZW4gdHJ5IHNwbGl0dGluZyBhZ2Fpbi4KClNpbmNlIHdlIG9yaWdpbmFsbHkgc3BsaXQgYmFzZWQgb24gdHdvIG9yIG1vcmUgc3BhY2VzLCB3ZSBjYW4ganVzdCBhZGQgYSBzcGFjZSBpbiBmcm9udCBvZiB0aGUgd29yZCAiTWVhbiIgZm9yIGFsbCB0aGUgYHBkZl90YWJsZWAgc3RyaW5ncyBhbmQgdGhlbiB0cnkgc3Vic2V0dGluZyBhZ2Fpbi4gV2UgY2FuIHVzZSB0aGUgYHN0cl93aGljaCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gZmluZCB0aGUgaW5kZXggb2YgdGhlc2UgcGFydGljdWxhciBjYXNlcy4KCmBgYHtyfQpwZGZfdGFibGUgJT4lCnN0cl93aGljaChwYXR0ZXJuID0gInNlYWZvb2R8c3VnYXIiKQpgYGAKCkhlcmUgd2UgY2FuIHVzZSB0aGlzIGZ1bmN0aW9uIHdpdGggYFtdYCB0byBzZWUganVzdCB0aGUgc3RyaW5ncyB0aGF0IG1hdGNoIHRoZXNlIHBhdHRlcm5zIHdpdGhpbiBgcGRmX3RhYmxlYDoKYGBge3J9CnBkZl90YWJsZVtzdHJfd2hpY2gocGRmX3RhYmxlLCBwYXR0ZXJuID0gInNlYWZvb2R8c3VnYXIiKV0KYGBgCgpOb3cgd2UgY2FuIHJlcGxhY2UgdGhlc2UgdmFsdWVzIHdpdGhpbiB0aGUgcGRmX3RhYmxlIG9iamVjdCBhZnRlciBhZGRpbmcgYSBzcGFjZSBpbiBmcm9udCBvZiAiTWVhbiI6CgpgYGB7cn0KcGRmX3RhYmxlW3N0cl93aGljaChwZGZfdGFibGUsIAogICAgICBwYXR0ZXJuID0gCiAgICAgICJzZWFmb29kfHN1Z2FyIildIDwtIHN0cl9yZXBsYWNlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nID0gcGRmX3RhYmxlW3N0cl93aGljaChwZGZfdGFibGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzZWFmb29kfHN1Z2FyIildLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJNZWFuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiIE1lYW4iKQpgYGAKCkFuZCBub3cgd2UgY2FuIHRyeSBzcGxpdHRpbmcgYWdhaW4gYnkgdHdvIG9yIG1vcmUgc3BhY2VzOgpgYGB7cn0KdGFibGVfc3BsaXQgPC0gc3RyX3NwbGl0KHBkZl90YWJsZSwgcGF0dGVybiA9ICJcXHN7Mix9IikKYGBgCgpXZSBjb3VsZCBhbHNvIGp1c3QgYWRkIGEgc3BhY2UgaW4gZnJvbnQgb2YgYWxsIHRoZSB2YWx1ZXMgb2YgIk1lYW4iIGluIGBwZGZfdGFibGVgIHNpbmNlIHRoZSBzcGxpdCB3YXMgcGVyZm9ybWVkIGJhc2VkIG9uIHR3byBvciBtb3JlIHNwYWNlcy4gVGh1cyB0aGUgb3RoZXIgZWxlbWVudHMgaW4gYHBkZl90YWJsZWAgd291bGQgYWxzbyBiZSBzcGxpdCBqdXN0IGFzIGJlZm9yZSBkZXNwaXRlIHRoZSBhZGRpdGlvbmFsIHNwYWNlLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KcGRmX3RhYmxlIDwtIHBkZl90YWJsZSAlPiUKICBzdHJpbmdyOjpzdHJfcmVwbGFjZShwYXR0ZXJuID0gIk1lYW4iLCAKICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIiBNZWFuIikKdGFibGVfc3BsaXQgPC0gc3RyX3NwbGl0KHBkZl90YWJsZSwgcGF0dGVybiA9ICJcXHN7Mix9IikKYGBgCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQojc2Nyb2xsIHRoZSBvdXRwdXQhCmdsaW1wc2UodGFibGVfc3BsaXQpIApgYGAKIyMjIwoKTG9va3MgYmV0dGVyIQoKV2Ugd2FudCBqdXN0IHRoZSBmaXJzdCAodGhlIGZvb2QgKipjYXRlZ29yeSoqKSBhbmQgdGhpcmQgY29sdW1uICh0aGUgb3B0aW1hbCBjb25zdW1wdGlvbiAqKmFtb3VudCoqIHN1Z2dlc3RlZCkgZm9yIGVhY2ggcm93IGluIHRoZSB0YWJsZS4gSG93ZXZlciwgdGhlIHRhYmxlIGlzIGN1cnJlbnQgc3RvcmVkIGFzIGEgbGlzdCBvZiBjaGFyYWN0ZXIgdmVjdG9ycywgc28gaXQgaXMgbm90IHF1aXRlIHNvIHNpbXBsZSB0byBleHRyYWN0IHRoZXNlIHZhbHVlcy4KCldlIGNhbiB1c2UgdGhlIGBtYXBgIGZ1bmN0aW9uIG9mIHRoZSBgcHVycnJgIHBhY2thZ2UgdG8gYWNjb21wbGlzaCB0aGlzLgoKVGhlIGBtYXBgIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBwZXJmb3JtIHRoZSBzYW1lIGFjdGlvbiBtdWx0aXBsZSB0aW1lcyBhY3Jvc3MgZWFjaCBlbGVtZW50IHdpdGhpbiBhbiBvYmplY3QsIGluIHRoaXMgY2FzZSwgYSBsaXN0LgoKVGhlIGZvbGxvd2luZyB3aWxsIGFsbG93IHVzIHRvIHNlbGVjdCB0aGUgZmlyc3Qgb3IgdGhpcmQgc3Vic3RyaW5nIGZyb20gZWFjaCBlbGVtZW50IG9mIHRoZSBgcGRmX3RhYmxlYCBvYmplY3QuCgpgYGB7cn0KY2F0ZWdvcnkgPC0gbWFwKHRhYmxlX3NwbGl0LCAxKQphbW91bnQgPC0gbWFwKHRhYmxlX3NwbGl0LCAzKQpoZWFkKGNhdGVnb3J5KQpoZWFkKGFtb3VudCkKYGBgCgpOb3cgd2Ugd2lsbCBjcmVhdGUgYSBgdGliYmxlYCB1c2luZyB0aGlzIGRhdGEuIEhvd2V2ZXIsIGN1cnJlbnRseSBib3RoIGBjYXRlZ29yeWAgYW5kIGBhbW91bnRgIGFyZSBvZiBjbGFzcyBgbGlzdGAuIFRvIGNyZWF0ZSBhIGB0aWJibGVgIHdlIG5lZWQgdG8gdW5saXN0IHRoZSBkYXRhIHRvIGNyZWF0ZSB2ZWN0b3JzLgoKYGBge3J9CmNsYXNzKGNhdGVnb3J5KQpjYXRlZ29yeSAlPD4lIHVubGlzdCgpCmFtb3VudCAlPD4lIHVubGlzdCgpCmNsYXNzKGNhdGVnb3J5KQpgYGAKCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CmNhdGVnb3J5CmFtb3VudApgYGAKIyMjIwoKV2UgY291bGQgaGF2ZSBkb25lIGFsbCBvZiB0aGlzIGF0IG9uY2UgaW4gb25lIGNvbW1hbmQgbGlrZSB0aGlzOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KY2F0ZWdvcnkgPC0gdW5saXN0KG1hcCh0YWJsZV9zcGxpdCwxKSkKYW1vdW50IDwtIHVubGlzdChtYXAodGFibGVfc3BsaXQsMykpCmBgYAoKTm93IHdlIHdpbGwgY3JlYXRlIGEgYHRpYmJsZWAsIHdoaWNoIGlzIGFuIGltcG9ydGFudCBkYXRhIGZyYW1lIHN0cnVjdHVyZSBpbiB0aGUgdGlkeXZlcnNlIHdoaWNoIGFsbG93cyB1cyB0byB1c2Ugb3RoZXIgcGFja2FnZXMgaW4gdGhlIHRpZHl2ZXJzZSB3aXRoIG91ciBkYXRhLgoKV2Ugd2lsbCBuYW1lIG91ciBgdGliYmxlYCBjb2x1bW5zIG5vdyBhcyB3ZSBjcmVhdGUgb3VyIGB0aWJibGVgIHVzaW5nIHRoZSBgdGliYmxlKClgIGZ1bmN0aW9uIG9mIGJvdGggdGhlIGB0aWR5cmAgYW5kIHRoZSBgdGliYmxlYCBwYWNrYWdlcywgYXMgbmFtZXMgYXJlIHJlcXVpcmVkIGluIHRpYmJsZXMuCgpgYGB7cn0KZ3VpZGVsaW5lcyA8LSB0aWJibGU6OnRpYmJsZShjYXRlZ29yeSA9IGNhdGVnb3J5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW1vdW50ID0gYW1vdW50KQpndWlkZWxpbmVzCmBgYAoKTG9va2luZyBwcmV0dHkgZ29vZCEKCiMjIyBTZXBhcmF0aW5nIHZhbHVlcyB3aXRoaW4gYSB2YXJpYWJsZQoKUmVjYWxsIHRoYXQgdGhlIG1haW4gZ29hbCBvZiB0aGlzIGRhdGEgd3JhbmdsaW5nIGlzIHRvIGV4dHJhY3QgdGhlIG9wdGltYWwgaW50YWtlIGxldmVsIGZvciBlYWNoIGRpZXRhcnkgZmFjdG9yLiBTbyB3aGlsZSB3ZSBoYXZlIG1hbmFnZWQgdG8gcHVsbCBhbmQgb3JnYW5pemUgdGhlIGRhdGEgZnJvbSB0aGUgcGRmIHRhYmxlLCB3ZSBuZWVkIHRvIGZ1cnRoZXIgcHJvY2VzcyB0aGUgcmVzdWx0cyB0byBpc29sYXRlIHRoaXMgbnVtZXJpYyB2YWx1ZS4KCkRvIHRvIHRoaXMsIHdlIHdhbnQgdG8gc2VwYXJhdGUgdGhlIGRpZmZlcmVudCBudW1iZXJzIHdpdGhpbiB0aGUgYGFtb3VudGAgY29sdW1uLCB0byBpc29sYXRlIHRoZSBvcHRpbWFsIGFtb3VudCwgYW5kIHRoZSBvcHRpbWFsIHJhbmdlLCBhbmQgZXZlbnR1YWxseSBjb252ZXJ0IHRoZW0gdG8gbnVtZXJpYyB2YWx1ZXMuCgpSZWNhbGwgd2hhdCB0aGUgb3JpZ2luYWwgdGFibGUgbG9va2VkIGxpa2U6CmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJmaXJzdHJvdy5wbmciKSkKYGBgCgpXZSBjYW4gdXNlIHRoZSBgdGlkeXI6OnNlcGFyYXRlKClgIGZ1bmN0aW9uIHRvIHNlcGFyYXRlIHRoZSBkYXRhIHdpdGhpbiB0aGUgYW1vdW50IGNvbHVtbiBpbnRvIHRocmVlIG5ldyBjb2x1bW5zIGJhc2VkIG9uIHRoZSBvcHRpbWFsIGxldmVsIGFuZCB0aGUgb3B0aW1hbCByYW5nZS4gV2UgY2FuIHNlcGFyYXRlIHRoZSB2YWx1ZXMgYmFzZWQgb24gdGhlIG9wZW4gcGFyZW50aGVzZXMgYCIoImAgYW5kIHRoZSBsb25nIGRhc2ggYCLigJMiYCBjaGFyYWN0ZXJzLiBBZ2FpbiB3ZSB3aWxsIHVzZSB0aGUgYmFyIGAifCJgIHRvIGluZGljYXRlIHRoYXQgd2Ugd2FudCB0byBzZXBhcmF0ZSBieSBlaXRoZXIgY2hhcmFjdGVyLgoKYGBge3J9CiMgVGhlIGZpcnN0IGNvbHVtbiB3aWxsIGJlIGNhbGxlZCBvcHRpbWFsCiMgSXQgd2lsbCBjb250YWluIHRoZSAxc3QgcGFydCBvZiB0aGUgYW1vdW50IGNvbHVtbiBkYXRhIGJlZm9yZSB0aGUgIigiCiMgVGhlIDJuZCBjb2x1bW4gd2lsbCBiZSBjYWxsZWQgbG93ZXIKIyBJdCB3aWxsIGNvbnRhaW4gdGhlIGRhdGEgYWZ0ZXIgdGhlICIoIgojIFRoZSAzcmQgY29sdW1uIHdpbGwgYmUgY2FsbGVkIHVwcGVyIAojIEl0IHdpbGwgY29udGFpbiB0aGUgMm5kIHBhcnQgb2YgdGhlIGRhdGEgYmFzZWQgb24gdGhlICLigJMiCiMgVGhlICJbXSIgYXJlIG5lY2Vzc2FyeSAtIHdlIHdpbGwgZXhwbGFpbiB2ZXJ5IHNvb24KCmd1aWRlbGluZXMgJTw+JSAKICB0aWR5cjo6c2VwYXJhdGUoYW1vdW50LCAKICAgICAgICAgICAgICAgICAgYygib3B0aW1hbCIsICJsb3dlciIsICJ1cHBlciIpLAogICAgICAgICAgICAgICAgICBzZXAgPSAiWyh84oCTXSIpIAoKZ3VpZGVsaW5lcwoKYGBgCgoKTGV0J3MgYWxzbyBjcmVhdGUgYSBuZXcgdmFyaWFibGUvY29sdW1uIGluIG91ciB0aWJibGUgdGhhdCBpbmRpY2F0ZXMgdGhlIGRpcmVjdGlvbiBvZiBvdmVyLSBvciB1bmRlci1jb25zdW1wdGlvbiB0aGF0IGNhbiBiZSBoYXJtZnVsIGZvciBlYWNoIGRpZXRhcnkgZmFjdG9yLgoKYGBge3J9Cmd1aWRlbGluZXMgJTw+JQogIHNlcGFyYXRlKGNhdGVnb3J5LCBjKCJkaXJlY3Rpb24iLCAiZm9vZCIpLCBzZXAgPSAiIGluICIpCmd1aWRlbGluZXMKYGBgCgpJZiB3ZSB3YW50ZWQgdG8gcmVtb3ZlIHRoZSBkaXJlY3Rpb24gdmFyaWFibGUgd2UgY291bGQgdXNlIHRoZSBgbW9kaWZ5X2F0KClgIGZ1bmN0aW9uIG9mIHRoZSBgcHVycnJgIHBhY2thZ2U6CgpgYGB7cixldmFsID0gRkFMU0V9Cmd1aWRlbGluZXMgJT4lIHB1cnJyOjptb2RpZnlfYXQoImRpcmVjdGlvbiIsIH4gTlVMTCkKYGBgCgoKIyMjIERhdGEgY2xlYW5pbmcgd2l0aCByZWd1bGFyIGV4cHJlc3Npb25zCgpPSywgbG9va2luZyBiZXR0ZXIsIGJ1dCB3ZSBzdGlsbCBuZWVkIGEgYml0IG9mIGNsZWFuaW5nIHRvIHJlbW92ZSBzeW1ib2xzIGFuZCBleHRyYSB3b3JkcyBmcm9tIHRoZSBjb2x1bW5zLiBTb21lIG9mIHRoZSBleHRyYSBzeW1ib2xzIGluY2x1ZGU6IGAiJSJgLCBgIikiYCBhbmQgdGhlIGAiKiJgLgoKVGhlIGAiKiJgIGFuZCB0aGUgYCIpImAgYXJlIHdoYXQgd2UgY2FsbCBtZXRhY2hhcmFjdGVycyBvciBbcmVndWxhciBleHByZXNzaW9uc10oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vcmVndWxhci1leHByZXNzaW9ucy1ldmVyeS1yLXByb2dyYW1tZXItc2hvdWxkLWtub3cvKXt0YXJnZXQ9Il9ibGFuayJ9LiBUaGVzZSBhcmUgY2hhcmFjdGVycyB0aGF0IGhhdmUgc3BlY2lhbCBtZWFuaW5ncy4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJSZWdFeENoZWF0c2hlZXQucG5nIikpCmBgYAoKTm93IHdlIG5lZWQgdGhlIGAiXFwiYCB0byBpbmRpY2F0ZSB0aGF0IHdlIHdhbnQgdGhlc2UgY2hhcmFjdGVycyB0byBiZSBtYXRjaGVkIGV4YWN0bHkgYW5kIG5vdCBpbnRlcnByZXRlZCBhcyB0aGUgbWVhbmluZyBvZiB0aGUgc3ltYm9sLiBQcmV2aW91c2x5IHdlIHVzZWQgYFtdYCBhcm91bmQgdGhlIGNoYXJhY3RlcnMgd2hlbiB3ZSBzZXBhcmF0ZWQgdGhlIG9wdGltYWwgYW1vdW50IGNvbHVtbnMuIFJlY2FsbCB0aGF0IHdlIHVzZWQgYCJbKHzigJNdImAuIFRoaXMgd29ya2VkIGJlY2F1c2UgdGhlc2UgYXJlIHB1bmN0dWF0aW9uIGNoYXJhY3RlcnMsIHdlIGNvdWxkIGhhdmUgYWxzbyB1c2VkIGAiXFwofOKAkyJgLgoKU2VlIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc3RyaW5nci92aWduZXR0ZXMvcmVndWxhci1leHByZXNzaW9ucy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm8gYWJvdXQgcmVndWxhciBleHByZXNzaW9ucyBpbiBSLiAKCioqKgoKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBhIHNpbXBsZSBleGFtcGxlIG9mIHJlZ3VsYXIgZXhwcmVzc2lvbnMgdXNpbmcgdGhlIGBzdHJfY291bnQoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIDwvc3VtbWFyeT4KClRoZSBgc3RyX2NvdW50KClgIGZ1bmN0aW9uIGNvdW50cyB0aGUgbnVtYmVyIG9mIGluc3RhbmNlcyBvZiBhIGNoYXJhY3RlciBzdHJpbmcuIEluIHRoaXMgY2FzZSB3ZSB3aWxsIGxvb2sgZm9yIGluZGl2aWR1YWwgY2hhcmFjdGVycyBidXQgeW91IGNvdWxkIGFsc28gc2VhcmNoIGZvciB3b3JkcyBvciBwaHJhc2VzLgoKYGBge3J9CnJlZ2V4dGVzdCA8LSByZWFkcjo6cmVhZF9maWxlKGhlcmUoImRvY3MiLCAicmVnRXgudHh0IikpCnJlZ2V4dGVzdApgYGAKCkNvdW50IHRoZSBsZXR0ZXIgdDoKYGBge3J9CnN0cl9jb3VudChyZWdleHRlc3QsICJ0IikgIyBub3RpY2UgdGhpcyBkb2Vzbid0IGluY2x1ZGUgdGhlIHQgaW4gdGhlIHRhYgpgYGAKCkNvdW50IHRhYnM6CmBgYHtyfQpzdHJfY291bnQocmVnZXh0ZXN0LCJcXHQiKSAjIHNlYXJjaCBmb3IgdGFiCiMgdGhpcyB3b3VsZCBub3Qgd29yazoKc3RyX2NvdW50KHJlZ2V4dGVzdCwiW3RdIikgIyBzZWFyY2hlcyBmb3IgdGhlIGxldHRlciB0CmBgYAoKQ291bnQgcGFyZW50aGVzZXM6CmBgYHtyfQojIHRoaXMgd291bGQgbm90IHdvcmsgYmVjYXVzZSByIHRoaW5rcyB0aGlzIGlzIHBhcnQgb2YgdGhlIGNvZGUgaXRzZWxmCiMgc3RyX2NvdW50KHJlZ2V4dGVzdCwgIikiKSAKIyB0aGlzIHdvdWxkIG5vdCB3b3JrIGJlY2F1c2UgciB0aGlua3MgdGhpcyBpcyBwYXJ0IG9mIHRoZSBjb2RlIGl0c2VsZgojIHN0cl9jb3VudChyZWdleHRlc3QsICJcKSIpCnN0cl9jb3VudChyZWdleHRlc3QsICJcXCkiKSAjIHRoaXMgd29ya3MhCiMgdGhpcyB3b3JrcyEgYmVjYXVzZSBpdCBpcyBhIHB1bmN0dWF0aW9uIGNoYXJhY3RlcgpzdHJfY291bnQocmVnZXh0ZXN0LCAiWyldIikgCmBgYAoKQ291bnQgdGhlIG9jY3VycmVuY2Ugb2YgdGhlIGFzdGVyaXg6CmBgYHtyfQojIHRoaXMgYWxzbyBkb2VzIG5vdCB3b3JrCiMgc3RyX2NvdW50KHJlZ2V4dGVzdCwgIioiKQojIG5vciBkb2VzIHRoaXMKIyBzdHJfY291bnQocmVnZXh0ZXN0LCAiXCoiKQpzdHJfY291bnQocmVnZXh0ZXN0LCAiXFwqIikgIyB0aGlzIHdvcmtzIQojIHRoaXMgd29ya3MhIGJlY2F1c2UgaXQgaXMgYSBwdW5jdHVhdGlvbiBjaGFyYWN0ZXIKc3RyX2NvdW50KHJlZ2V4dGVzdCwgIlsqXSIpICMgdGhpcyB3b3JrcyEKCmBgYAoKPC9kZXRhaWxzPgoKKioqCgpXZSBhbHNvIHdhbnQgdG8gbWFrZSBhIHVuaXQgdmFyaWFibGUgc28gdGhhdCB3ZSBjYW4gbWFrZSBzdXJlIHRoYXQgb3VyIHVuaXRzIGFyZSBjb25zaXN0ZW50IGxhdGVyLiAKCmBgYHtyfQpndWlkZWxpbmVzICU+JQpwdWxsKG9wdGltYWwpIApgYGAKCk5vdGljZSB0aGF0IHRoZSB2YWx1ZXMgdGhhdCBhcmUgcGVyY2VudGFnZXMgZG9uJ3QgaGF2ZSBzcGFjZXMgYmV0d2VlbiB0aGUgbnVtYmVyIGFuZCB0aGUgdW5pdC4KV2UgY2FuIHNlcGFyYXRlIHRoZSBgIm9wdGltYWwiYCB2YWx1ZXMgYnkgYSBzcGFjZSBvciBhIHBlcmNlbnQgc3ltYm9sIGAiJSJgIHVzaW5nIGAifCJgIHRvIGluZGljYXRlIHRoYXQgd2Ugd2FudCB0byBzZXBhcmF0ZSBieSBlaXRoZXIuIEluIHRoaXMgY2FzZSB3ZSB3aWxsIGxvc2UgdGhlICIlIiBhbmQgd2lsbCBuZWVkIHRvIGFkZCBpdCBiYWNrIHRvIHRob3NlIHZhbHVlcy4KCmBgYHtyfQpndWlkZWxpbmVzICU8PiUKICBzZXBhcmF0ZShvcHRpbWFsLCBpbnRvID0gYygib3B0aW1hbCIsICJ1bml0IiksIAogICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIHwlIiwgCiAgICAgICAgICAgICAgICAgIHJlbW92ZSA9IEZBTFNFKQpndWlkZWxpbmVzCmBgYAoKR3JlYXQsIHNvIHRvIG5vdyB3ZSB3aWxsIGFkZCAiYCVgIiB0byB0aGUgYHVuaXRgIHZhcmlhYmxlIGZvciAgdGhlIGAibG93IGluIHBvbHl1bnNhdHVyYXRlZCJgIGFuZCBgImhpZ2ggaW4gdHJhbnMgZmF0dHkgYWNpZHMiYCByb3dzLgoKRmlyc3Qgd2UgbmVlZCB0byByZXBsYWNlIHRoZSBlbXB0eSB2YWx1ZXMgd2l0aCBgTkFgIHVzaW5nIHRoZSBgbmFfaWYoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KCmBgYHtyfQpndWlkZWxpbmVzICU8PiUKbmFfaWYoIiIpCmd1aWRlbGluZXMKYGBgCgoKVGhlbiB0byByZXBsYWNlIHRoZSBgTkFgIHZhbHVlcywgd2UgY2FuIHVzZSB0aGUgYHJlcGxhY2VfbmEoKWAgZnVuY3Rpb24gaW4gdGhlIGB0aWR5cmAgcGFja2FnZSBhbmQgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYCB0byBzcGVjaWZ5IHdoaWNoIHZhbHVlcyB0byByZXBsYWNlLCBpbiB0aGlzIGNhc2UgdGhlIGBOQWAgdmFsdWVzIHdpdGhpbiB0aGUgdmFyaWFibGUgYHVuaXRgLiBFc3NlbnRpYWxseSB0aGlzIHZhcmlhYmxlIGdldHMgcmVhc3NpZ25lZCB3aXRoIHRoZSBuZXcgdmFsdWVzLCBhcyB3ZSBtb3N0bHkgdGhpbmsgb2YgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gYXMgY3JlYXRpbmcgbmV3IHZhcmlhYmxlcy4KCmBgYHtyfQpndWlkZWxpbmVzICU8PiUgCiAgZHBseXI6Om11dGF0ZSh1bml0ID0gcmVwbGFjZV9uYSh1bml0LCAiJSIpKQoKIyBub3cganVzdCB0byBzaG93IHRoZXNlIHJvd3MKZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIodW5pdCA9PSAiJSIpCgpgYGAKCkxldCdzIGFsc28gbW92ZSBgdW5pdGAgdG8gYmUgdGhlIGxhc3QgY29sdW1uLiBXZSBjYW4gdXNlIHRoZSBgc2VsZWN0KClgIGFuZCBgZXZlcnl0aGluZygpYCBmdW5jdGlvbnMgb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBkbyB0aGlzLgoKYGBge3J9Cmd1aWRlbGluZXMgJTw+JQogIHNlbGVjdCgtdW5pdCwgZXZlcnl0aGluZygpKQpgYGAKCkhlcmUgeW91IGNhbiBzZWUgSGFkbGV5IFdpY2toYW0ncyAoQ2hpZWYgU2NpZW50aXN0IGF0IFJTdHVkaW8pIGV4cGxhbmF0aW9uIGZvciB0aGlzIGJlaGF2aW9yIG9mIGBzZWxlY3QoKWA6CgpgYGB7ciwgZWNobz0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJzZWxlY3QucG5nIikpCmBgYApodHRwczovL2dpdGh1Yi5jb20vdGlkeXZlcnNlL2RwbHlyL2lzc3Vlcy8yODM4I2lzc3VlY29tbWVudC0zMDYwNjI4MDAKClRvIHJlbW92ZSBhbGwgb2YgdGhlIHJlbWFpbmluZyBleHRyYSBjaGFyYWN0ZXJzIGFuZCB3b3JkcyB3ZSB3aWxsIGFnYWluIHVzZSB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIFRoaXMgdGltZSB3ZSB3aWxsIHVzZSB0aGUgYHN0cl9yZW1vdmVfYWxsKClgIGZ1bmN0aW9uIHRvIHJlbW92ZSBhbGwgaW5zdGFuY2VzIG9mIHRoZXNlIGNoYXJhY3RlcnMuCgpgYGB7cn0KZ3VpZGVsaW5lcyA8LSBhc190aWJibGUoCiAgbWFwKGd1aWRlbGluZXMsIHN0cl9yZW1vdmVfYWxsLAogICAgICBwYXR0ZXJuID0gIlxcKSBwZXIgZGF5fFxcKSBvZiB0b3RhbCBkYWlseSBlbmVyZ3l8XFwqIikpCmBgYAoKTmljZSEgdGhhdCdzIHByZXR0eSBjbGVhbiBidXQgd2UgY2FuIGRvIGEgYml0IG1vcmUuCgojIyMgRGF0YSB0eXBlIGNvbnZlcnNpb24KCk9uZSBvZiB0aGUgbmV4dCB0aGluZ3MgdG8gbm90aWNlIGFib3V0IG91ciBkYXRhIGlzIGFsbCBvZiBvdXIgdmFyaWFibGVzIGFyZSBvZiBjbGFzcyBjaGFyYWN0ZXIsIHdoaWNoIGlzIG5vdCBob3cgd2Ugd2FudCB0aGVtIHRvIGJlLgoKRm9yIGV4YW1wbGUsIHRoZSBvcHRpbWFsIGFtb3VudHMgb2YgY29uc3VtcHRpb24gYXJlIGN1cnJlbnRseSBvZiBjbGFzcyBjaGFyYWN0ZXIsIHdoaWNoIGlzIGluZGljYXRlZCBieSB0aGUgYDxjaHI+YCBqdXN0IGJlbG93IHRoZSBjb2x1bW4gbmFtZXMvdmFyaWFibGUgbmFtZXMgb2YgdGhlIGBndWlkZWxpbmVzYCB0aWJibGU6CgpgYGB7cn0KZ3VpZGVsaW5lcwpgYGAKCgpUbyBjb252ZXJ0IHRoZXNlIHZhbHVlcyB0byBudW1lcmljIHdlIGNhbiB1c2UgdGhlIGBtdXRhdGVfYXQoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KClRoZSBgbXV0YXRlX2F0KClgIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBwZXJmb3JtIGEgZnVuY3Rpb24gb24gc3BlY2lmaWMgY29sdW1ucy92YXJpYWJsZXMgd2l0aGluIGEgdGliYmxlLiBXZSBuZWVkIHRvIGluZGljYXRlIHdoaWNoIHZhcmlhYmxlcyB3ZSB3b3VsZCBsaWtlIHRvIGNvbnZlcnQgdXNpbmcgYHZhcnMoKWAuIEluIHRoaXMgY2FzZSBpZiB3ZSBsb29rIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGBndWlkZWxpbmVzYCB0aWJibGUsIHdlIGNhbiBzZWUgdGhhdCBgb3B0aW1hbGAsIGBsb3dlcmAgYW5kIGB1cHBlcmAgc2hvdWxkIGJlIGNvbnZlcnRlZC4gQXMgdGhlc2UgdGhyZWUgY29sdW1ucyBhcmUgc2VxdWVudGlhbCwgd2UgY2FuIHNpbXBseSBwdXQgYSBgOmAgYmV0d2VlbiBgb3B0aW1hbGAgYW5kIGB1cHBlcmAgdG8gaW5kaWNhdGUgdGhhdCB3ZSB3YW50IGFsbCB0aGUgdmFyaWFibGVzIGluIGJldHdlZW4gdGhlc2UgY29sdW1ucyB0byBiZSBjb252ZXJ0ZWQuIAoKYGBge3J9Cmd1aWRlbGluZXMgJTw+JQogIG11dGF0ZV9hdCh2YXJzKGxvd2VyOnVwcGVyKSwgYXMubnVtZXJpYykKZ3VpZGVsaW5lcwpgYGAKCkdyZWF0ISBOb3cgdGhlc2UgdmFyaWFibGVzIGFyZSBvZiBjbGFzcyBgPGRibD5gIChzdGFuZHMgZm9yIGRvdWJsZSkgd2hpY2ggaW5kaWNhdGVzIHRoYXQgdGhleSBhcmUgbnVtZXJpYy4gSGVyZSBpcyBhIFtsaW5rXShodHRwOi8vdWMtci5naXRodWIuaW8vaW50ZWdlcl9kb3VibGUvKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIG51bWVyaWMgY2xhc3NlcyBpbiBSLgoKSWYgd2UgaGFkIG5vdCByZXBsYWNlZCB0aGUgYCLCtyJgIGludGVycHVuY3QgdmFsdWVzIHRvIGEgcGVyaW9kLCBjb252ZXJzaW9uIGZyb20gY2hhcmFjdGVyIHRvIG51bWVyaWMgd291bGQgYmUgcHJvYmxlbWF0aWMgYW5kIHdvdWxkIHJlc3VsdCBpbiBOQSB2YWx1ZXMuCgojIyMgRGF0YSB2YWx1ZSByZWFzc2lnbm1lbnRzCgpXZSBzZWVtIHRvIGhhdmUgbG9zdCB0aGUgd29yZCBgImJldmVyYWdlcyJgIGZyb20gdGhlIGAic3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyJgIGNhdGVnb3J5LCAgYXMgd2VsbCBhcyBgImZhdHR5IGFjaWRzImAgZnJvbSB0aGUgYCJzZWFmb29kIG9tZWdhIDMgZmF0dHkgYWNpZHMiYCwgYW5kIHRoZSBgInBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcyJgIGNhdGVnb3JpZXMgYXMgdGhlIGZ1bGwgY2F0ZWdvcnkgbmFtZSB3YXMgbGlzdGVkIG9uIHR3byBsaW5lcyB3aXRoaW4gdGhlIHRhYmxlLiBXZSB3b3VsZCBsaWtlIHRvIHJlcGxhY2UgdGhlc2UgdmFsdWVzIHdpdGggdGhlIGZ1bGwgbmFtZS4gCgpUbyBzZWxlY3QgdGhlIGBmb29kYCB2YXJpYWJsZSB3ZSB3aWxsIHNob3cgeW91IHNldmVyYWwgb3B0aW9ucy4gT25seSBhIGNvdXBsZSB3aWxsIHdvcmsgd2VsbCB3aXRoIHJlYXNzaWduaW5nIHRoZSBkYXRhIGluIHRoYXQgcGFydGljdWxhciB2YXJpYWJsZSB3aXRoaW4gYGd1aWRlbGluZXNgIHdpdGhvdXQgYXNzaWduaW5nIGFuIGludGVybWVkaWF0ZSBkYXRhIG9iamVjdC4gV2Ugd2lsbCBsb29rIHVzaW5nIGBtdXRhdGVfYXQoKWAsIGBwdWxsKClgLCBgc2VsZWN0KClgLCBhbmQgdHdvIHN0eWxlcyBvZiBicmFja2V0cyBgWyJ2YXJpYWJsZSBuYW1lIl1gIGFuZCBgW1sidmFyaWFibGVuYW1lIl1dYC4KClRoZSBicmFja2V0IGBbInZhcmlhYmxlIG5hbWUiXWAgb3B0aW9uIGFuZCB0aGUgc2VsZWN0KCkgb3B0aW9uIHdpbGwgZ3JhYiBhIHRpYmJsZSAoZGF0YSBmcmFtZSkgdmVyc2lvbiBvZiB0aGUgZm9vZCBjb2x1bW4gb3V0IG9mIGd1aWRlbGluZXMuIEhvd2V2ZXIgd2UgY2FuJ3Qgc3RhcnQgY29tbWFuZHMgd2l0aCBzZWxlY3QgZm9yIGFzc2lnbm1lbnRzLgoKYGBge3J9Cmd1aWRlbGluZXNbImZvb2QiXSAjIHNhbWUgb3V0cHV0IGFzIHNlbGVjdApzZWxlY3QoZ3VpZGVsaW5lcywgImZvb2QiKSAjIHNhbWUgb3V0cHV0IGFzIGJyYWNrZXRzCmBgYAoKCmBwdWxsKClgIGFuZCB0aGUgYnJhY2tldCBgW1sidmFyaWFibGUgbmFtZSJdXWAgb3B0aW9uIGluIGNvbnRyYXN0LCB3aWxsIGdyYWIgdGhlIHZlY3RvciB2ZXJzaW9uIG9mIHRoZSBmb29kIGRhdGE6CgpgYGB7cn0KcHVsbChndWlkZWxpbmVzLCAiZm9vZCIpICMgZ2V0IGNoYXJhY3RlciB2ZWN0b3Igbm90IGEgdGliYmxlCiMgYnJhY2tldCBvcHRpb246Cmd1aWRlbGluZXNbWyJmb29kIl1dICMgZ2V0IGNoYXJhY3RlciB2ZWN0b3Igbm90IGEgdGliYmxlCmBgYAoKVGhlIGBwdWxsKClgIGZ1bmN0aW9uIGNhbiBiZSB2ZXJ5IHVzZWZ1bCB3aGVuIGNvbWJpbmVkIHdpdGggb3RoZXIgZnVuY3Rpb25zIChmb3IgZXhhbXBsZSB5b3UgdHlwaWNhbGx5IHdhbnQgdG8gdXNlIGEgdmVjdG9yIHdpdGggdGhlIGBzdHJfcmVwbGFjZSgpYCBmdW5jdGlvbiksIGJ1dCBqdXN0IGxpa2Ugc2VsZWN0LCB3ZSBjYW4ndCBzdGFydCBhc3NpZ25tZW50cyB3aXRoIGBwdWxsKClgLgoKClRoaXMgaXMgbm90IHBvc3NpYmxlIGFuZCB3aWxsIHJlc3VsdCBpbiBhbiBlcnJvcjoKYGBge3IsIGV2YWwgPSBGQUxTRX0Kc2VsZWN0KGd1aWRlbGluZXMsIGZvb2QpIDwtIAogICBzdHJfcmVwbGFjZSggCiAgIHB1bGwoZ3VpZGVsaW5lcywiZm9vZCIpLCAKICAgcGF0dGVybiA9ICJzdWdhci1zd2VldGVuZWQiLCAKICAgcmVwbGFjZW1lbnQgPSAic3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyIpCgpndWlkZWxpbmVzICU+JSBzZWxlY3QoZm9vZCkgPC0gCiAgIHN0cl9yZXBsYWNlKCAKICAgcHVsbChndWlkZWxpbmVzLCJmb29kIiksIAogICBwYXR0ZXJuID0gInN1Z2FyLXN3ZWV0ZW5lZCIsIAogICByZXBsYWNlbWVudCA9ICJzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2VzIikKYGBgCgpUaGlzIHdpbGwgb25seSBwcmludCB0aGUgcmVzdWx0LCBidXQgbm90IHJlYXNzaWduIHRoZSBmb29kIHZhcmlhYmxlIHZhbHVlczoKCmBgYHtyfQpndWlkZWxpbmVzICU+JQogICBwdWxsKGZvb2QpICU+JQogICBzdHJfcmVwbGFjZSggCiAgIHBhdHRlcm4gPSAic3VnYXItc3dlZXRlbmVkIiwgCiAgIHJlcGxhY2VtZW50ID0gInN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMiKQpgYGAgICAKClVzaW5nIGBzZWxlY3QoKWAgd291bGQgd29yayBhcyB3ZWxsIHRvIHByaW50IHRoZSByZXN1bHQgKGFsdGhvdWdoIHRoZSByZXN1bHQgc3RydWN0dXJlIGlzIGRpZmZlcmVudCk6CgpgYGB7cn0KZ3VpZGVsaW5lcyAlPiUKICAgc2VsZWN0KGZvb2QpICU+JQogICBzdHJfcmVwbGFjZSggCiAgIHBhdHRlcm4gPSAic3VnYXItc3dlZXRlbmVkIiwgCiAgIHJlcGxhY2VtZW50ID0gInN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMiKQoKYGBgCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9Cgo8dT5RdWVzdGlvbiBvcHBvcnR1bml0eTo8L3U+IAoKV2h5IGRvIHRoZXNlIGNvbW1hbmRzIG5vdCByZWFzc2lnbiB0aGUgZm9vZCB2YXJpYWJsZSB2YWx1ZXM/CgojIyMjCgpUaGUgYnJhY2tldCBvcHRpb24gaXMgZ3JlYXQgYWx0ZXJuYXRpdmUgYW5kIGFsbG93cyB1cyB0byByZWFzc2lnbiB0aGUgdmFsdWVzIHdpdGhpbiBndWlkZWxpbmVzIGVhc2lseS4gRWl0aGVyIG9mIHRoZSB0d28gc3R5bGVzIG9mIGJyYWNrZXRzOiBgWyJ2YXJpYWJsZSBuYW1lIl1gIGFuZCBgW1sidmFyaWFibGVuYW1lIl1dYCB3aWxsIHdvcmsuCgpgYGB7cn0KIyAxc3QgbWV0aG9kOiBgWyJ2YXJpYWJsZSBuYW1lIl1gCiMgUmVwbGFjaW5nICJzdWdhci1zd2VldGVuZWQiIHdpdGggInN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMiCmd1aWRlbGluZXNbImZvb2QiXSA8LSAKICBzdHJfcmVwbGFjZSggCiAgcHVsbChndWlkZWxpbmVzLCJmb29kIiksIAogIHBhdHRlcm4gPSAic3VnYXItc3dlZXRlbmVkIiwgCiAgcmVwbGFjZW1lbnQgPSAic3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyIpCgojIDJuZCBtZXRob2Q6IGBbWyJ2YXJpYWJsZW5hbWUiXV1gCiMgUmVwbGFjaW5nICJzZWFmb29kIG9tZWdhLTMiIHdpdGgic2VhZm9vZCBvbWVnYS0zIGZhdHR5IGFjaWRzIgpndWlkZWxpbmVzW1siZm9vZCJdXSA8LSAKICBzdHJfcmVwbGFjZSggCiAgcHVsbChndWlkZWxpbmVzLCJmb29kIiksIAogIHBhdHRlcm4gPSAic2VhZm9vZCBvbWVnYS0zIiwgCiAgcmVwbGFjZW1lbnQgPSAic2VhZm9vZCBvbWVnYS0zIGZhdHR5IGFjaWRzIikKCmd1aWRlbGluZXMKYGBgCgoKRmluYWxseSwgdGhlIGJlc3Qgb3B0aW9uIGlzIHByb2JhYmx5IHRoZSBgbXV0YXRlX2F0KClgIGZ1bmN0aW9uIGZyb20gYGRwbHlyYC4gSW4gdGhpcyBjYXNlIHdlIG5lZWQgdG8gaW5jbHVkZSBgfmAgaW4gZnJvbnQgb2YgdGhlIGZ1bmN0aW9uIHRoYXQgd2Ugd291bGQgbGlrZSB0byB1c2Ugb24gdGhlIHZhbHVlcyBpbiBvdXIgYGZvb2RgIHZhcmlhYmxlcy4gV2UgYWxzbyBpbmNsdWRlIGAuYCBhcyBhIHJlcGxhY2VtZW50IHRvIHJlZmVyZW5jZSB0aGUgZGF0YSB0aGF0IHdlIHdhbnQgdG8gdXNlIHdpdGhpbiBgc3RyX3JlcGxhY2UoKWAgKHdoaWNoIGluIHRoaXMgY2FzZSBpcyB0aGUgYGZvb2RgIHZhcmlhYmxlIHZhbHVlcyBvZiBgZ3VpZGVsaW5lc2ApLgoKTm90aWNlIHdlIGRpZG4ndCBuZWVkIHRoaXMgd2hlbiB3ZSBwcmV2aW91c2x5IHVzZSBgbXV0YXRlX2F0KClgIHdpdGggdGhlIGBhcy5udW1lcmljKClgIGZ1bmN0aW9uLiBUaGlzIGlzIGJlY2F1c2UgdGhlIGBzdHJfcmVwbGFjZSgpYCBmdW5jdGlvbiByZXF1aXJlcyB1cyB0byBzcGVjaWZ5IHdoYXQgZGF0YSB3ZSBhcmUgdXNpbmcgYXMgb25lIG9mIHRoZSBhcmd1bWVudHMsIHdoaWxlIGBhcy5udW1lcmljKClgIGRvZXMgbm90LgoKYGBge3J9CgojIFJlcGxhY2luZyAicG9seXVuc2F0dXJhdGVkIiB3aXRoInBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcyIKZ3VpZGVsaW5lcyAlPD4lCiAgbXV0YXRlX2F0KHZhcnMoZm9vZCksCiAgfnN0cl9yZXBsYWNlKCAKICBzdHJpbmcgPSAuLCAKICBwYXR0ZXJuID0gInBvbHl1bnNhdHVyYXRlZCIsIAogIHJlcGxhY2VtZW50ID0gInBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcyIpKQoKZ3VpZGVsaW5lcwoKYGBgCgpUaGlzIG1pZ2h0IGJlIGNvbnNpZGVyZWQgYSBiZXR0ZXIgb3B0aW9uIGJlY2F1c2UgaXQgaXMgbW9yZSByZWFkYWJsZSBhcyB0byB3aGVyZSB0aGUgYGZvb2RgIGRhdGEgY2FtZSBmcm9tIHRoYXQgd2UgYXJlIHJlcGxhY2luZyB2YWx1ZXMgd2l0aGluLgoKVGhlcmUgaXMgb25lIGxhc3QgbWlub3IgZGV0YWlsLi4uIHRoZSBgZGlyZWN0aW9uYCB2YXJpYWJsZSBoYXMgbGVhZGluZyBzcGFjZXMgc3RpbGwuIFdlIGNhbiB1c2UgYHN0cl90cmltKClgIHRvIGZpeCB0aGF0IQoKYGBge3J9Cmd1aWRlbGluZXMgJTw+JQogIG11dGF0ZV9hdCh2YXJzKGRpcmVjdGlvbiksIHN0cl90cmltKQoKZ3VpZGVsaW5lcwpgYGAKCk9LISBOb3cgd2Uga25vdyBob3cgbXVjaCBvZiBlYWNoIGRpZXRhcnkgZmFjdG9yIHdlIGdlbmVyYWxseSBuZWVkIGZvciBvcHRpbWFsIGhlYWx0aCBhY2NvcmRpbmcgdG8gdGhlIGd1aWRlbGluZXMgdXNlZCBpbiB0aGlzIGFydGljbGUuCgoKCiMjIyBDb21wYXJpbmcgZGF0YQoKUmVjYWxsIHRoYXQgdGhlIG1haW4gZ29hbCBvZiBwdWxsaW5nIHRoZSBndWlkZWxpbmUgYW1vdW50cyBmcm9tIHRoZSBwZGYgd2FzIHRoYXQgd2Ugd291bGQgbGlrZSB0byBzZWUgaG93IHRoZSBtZWFuIGNvbnN1bXB0aW9uIHJhdGVzIGZvciB0aGUgZGlmZmVyZW50IGdyb3VwcyBvZiBwZW9wbGUgY29tcGFyZWQgdG8gdGhlIG9wdGltYWwgaW50YWtlIGd1aWRlbGluZXMuCgpPbmUgd2F5IHdlIGNvdWxkIGRvIHRoaXMgaXMgdG8gY2FsY3VsYXRlIGEgY29uc3VtcHRpb24gcGVyY2VudGFnZSBvZiB0aGUgb3B0aW1hbCB2YWx1ZS4KClRvIGNhbGN1bGF0ZSB0aGlzIGl0IHdvdWxkIGJlIGhlbHBmdWwgdG8gcHV0IHRoZSBndWlkZWxpbmUgYW1vdW50cyB3aXRoIHRoZSBhdmVyYWdlIGNvbnN1bXB0aW9uIHJhdGVzIGludG8gdGhlIHNhbWUgdGliYmxlLCBlc3BlY2lhbGx5IGJlY2F1c2UgdGhlIG9ic2VydmVkIGNvbnN1bXB0aW9uIGRhdGEgKGBkaWV0X2RhdGFgIGFuZCBgc2VwX2FnZV9kaWV0X2RhdGFgKSBhcmUgdmVyeSBkaWZmZXJlbnQgZGltZW5zaW9ucyBmcm9tIHRoZSBgZ3VpZGVsaW5lc2AgZGF0YS4gCgpJbiBvcmRlciB0byBjcmVhdGUgYSB0aWJibGUgd2l0aCBvdXIgb2JzZXJ2ZWQgY29uc3VtcHRpb24gcmF0ZXMgd2l0aCB0aGUgc3VnZ2VzdGVkIGNvbnN1bXB0aW9uIHJhdGVzLCB3ZSB3aWxsIGpvaW4gb3VyIGRhdGEgdXNpbmcgYGRwbHlyYC4gSW4gb3JkZXIgdG8gZG8gc28gaXQgaXMgaW1wb3J0YW50IHRoYXQgb3VyIGRpZmZlcmVudCBkYXRhIHNldHMgaGF2ZSBhdCBsZWFzdCBvbmUgY29sdW1uIHdpdGggdGhlIHNhbWUgdmFsdWVzIHRoYXQgd2UgY2FuIHVzZSB0byBqb2luIHRoZW0gdG9nZXRoZXIuIFNvIGxldCdzIGZpcnN0IGFzc2VzcyBpZiB0aGF0IGlzIHRoZSBjYXNlLgoKCmBgYHtyfQpkaXN0aW5jdChkaWV0X2RhdGEsIHJlaV9uYW1lKQpzZWxlY3QoZ3VpZGVsaW5lcywgZm9vZCkKYGBgCgpXZSBhcmUgYWN0dWFsbHkgcHJldHR5IGNsb3NlOiB0aGVyZSBhcmUgMTUgZGlldGFyeSBmYWN0b3JzIGluIGVhY2ggZGF0YSBzZXQsIGFuZCB0aGUgbmFtZXMgYXJlIG5lYXJseSB0aGUgc2FtZS4gVG8gbWFrZSB0aGVtIG1hdGNoIGNvbXBsZXRlbHksIHdlIGNhbiBzZWUgdGhhdCB3ZSBuZWVkIHRvIHJlbW92ZSB0aGUgYCJEaWV0IGxvdyBpbiJgIGFuZCBgIkRpZXQgaGlnaCBpbiJgIHBocmFzZXMgZnJvbSB0aGUgb2JzZXJ2ZWQgY29uc3VtcHRpb24gZGF0YS4KCmBgYHtyfQoKZGlldF9kYXRhICU8PiUKICBtdXRhdGVfYXQodmFycyhyZWlfbmFtZSksCiAgfiBzdHJfcmVtb3ZlKHN0cmluZyA9IC4sIAogICAgICAgICAgICAgcGF0dGVybiA9ICJEaWV0IGxvdyBpbiB8RGlldCBoaWdoIGluICIpKQoKc2VwX2FnZV9kaWV0X2RhdGEgJTw+JQogIG11dGF0ZV9hdCh2YXJzKHJlaV9uYW1lKSwKICB+IHN0cl9yZW1vdmUoc3RyaW5nID0gLiwKICAgICAgICAgICAgICBwYXR0ZXJuID0gIkRpZXQgbG93IGluIHxEaWV0IGhpZ2ggaW4gIikpCmBgYAoKQWxzbyBsZXQncyBkb3VibGUgY2hlY2sgdGhhdCB0aGUgdHdvIG9ic2VydmVkIGZpbGVzIGhhdmUgdGhlIHNhbWUgZXhhY3QgdmFsdWVzIGZvciBkaWV0YXJ5IGZhY3RvciBuYW1lcy4gCgpXZSBjYW4gdXNlIHRoZSBgc2V0ZXF1YWwoKWAgZnVuY3Rpb24gZnJvbSBgZHBseXJgIHRvIGNoZWNrIHRoYXQgdGhlIHVuaXF1ZSB2YWx1ZXMgZm9yIGByZWlfbmFtZWAgYXJlIHRoZSBzYW1lIGZvciBib3RoIGBkaWV0X2RhdGFgIGFuZCBgc2VwX2FnZV9kaWV0X2RhdGFgLgoKCmBgYHtyfQpzZXRlcXVhbChkaXN0aW5jdChkaWV0X2RhdGEsIHJlaV9uYW1lKSwgCiAgICAgICAgIGRpc3RpbmN0KHNlcF9hZ2VfZGlldF9kYXRhLCByZWlfbmFtZSkpCmBgYApHcmVhdCEKCk5vdGUgdGhhdCB0aGUgZGVmYXVsdCBvZiB0aGUgc2V0X2VxdWFsIGZ1bmN0aW9uIGlnbm9yZXMgdGhlIG9yZGVyIG9mIHZhbHVlcyBpbiByb3dzLiBTbyB3ZSBzdGlsbCBkb24ndCBrbm93IGlmIHRoZSBvcmRlciBpcyB0aGUgc2FtZS4KCldlIGNhbiBjaGVjayB1c2luZyB0aGUgYGFsbF9lcXVhbGAgZnVuY3Rpb24gb2YgYGRwbHlyYCB3aGljaCByZXBvcnRzIGJhY2sgY2x1ZXMgYWJvdXQgd2hhdCBtaWdodCBiZSBkaWZmZXJlbnQgaWYgYW55dGhpbmcuIEltcG9ydGFudGx5IHdlIGFyZSBpbmNsdWRpbmcgYGlnbm9yZV9yb3dfb3JkZXIgPSBGQUxTRWAgYXMgdGhlIGRlZmF1bHQgaXMgYFRSVUVgLgoKYGBge3J9CmFsbF9lcXVhbChkaXN0aW5jdChkaWV0X2RhdGEsIHJlaV9uYW1lKSwgCiAgICAgICAgICBkaXN0aW5jdChzZXBfYWdlX2RpZXRfZGF0YSwgcmVpX25hbWUpLCAKICAgICAgICAgIGlnbm9yZV9yb3dfb3JkZXIgPSBGQUxTRSkKYGBgCgpMb29rcyBsaWtlIHRoZXkgYXJlIGFsc28gaW4gdGhlIHNhbWUgb3JkZXIuIAoKTm90ZSB0aGF0IGlmIGFueSBvZiB0aGUgdmFsdWVzIGFyZSBkaWZmZXJlbnQsIGBhbGxfZXF1YWwoKWAgd2lsbCBmaXJzdCByZXBvcnQgdGhpcyBhbmQgd2lsbCBub3QgcmVwb3J0IHRoYXQgdGhlIHJvd3MgYXJlIGluIGEgZGlmZmVyZW50IG9yZGVyLgoKKioqCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGEgdG95IGV4YW1wbGUgYWJvdXQgaG93IHRoZSB0aHJlZSBjb21wYXJpc29uIGZ1bmN0aW9ucyAoYHNldGVxdWFsKClgLCBgYWxsX2VxdWFsKClgIChhbHNvIGBhbGwuZXF1YWwoKWAgZm9yIGB0YmxfZGZgKSwgYW5kIGBzZXRkaWZmKClgKSB3b3JrIGluIGBkcGx5cmAuIDwvc3VtbWFyeT4gCgpJdCdzIGltcG9ydGFudCB0byByZWFsaXplIHRoYXQgcm93IG9yZGVyIGlzIGlnbm9yZWQgYnkgYm90aGBzZXRlcXVhbCgpYCBhbmQgYHNldGRpZmYoKWAuIAoKTm93IGxldCdzIGNvbXBhcmUgdHdvIHRpYmJsZXMgdGhhdCBoYXZlIGRpZmZlcmVudCByb3cgb3JkZXJzIGFuZCBkaWZmZXJlbnQgdmFsdWVzLiAKCkhlcmUgYXJlIG91ciB0aWJibGVzIHRvIGNvbXBhcmU6CmBgYHtyfQpYIDwtIHRpYmJsZSh0ZXN0ID0gYygiQSIsICJCIiwgIkFDIiwgIkQiKSkKWSA8LSB0aWJibGUodGVzdCA9IGMoIkEiLCAiRCIsICJBIiwgIkIiKSkKWApZCmNsYXNzKFkpCmBgYAoKU2luY2Ugd2UgYXJlIHVzaW5nIHRpYmJsZXMsIHdoaWNoIGFyZSBvZiBjbGFzcyBgdGJsX2RmYCB3ZSBjYW4gdXNlIGVpdGhlciBgYWxsX2VxdWFsYCBvciBgYWxsLmVxdWFsKClgLgpOb3RpY2UgdGhhdCBpdCBkb2Vzbid0IHJlcG9ydCByb3dzIGJlaW5nIGEgZGlmZmVyZW50IG9yZGVyIGJlY2F1c2UgaXQgZmlyc3QgdGVsbHMgd2hhdCByb3dzIGhhdmUgdW5pcXVlIHZhbHVlcyBvciByb3dzIHdpdGggYSB2YWx1ZSB0aGF0IGhhcyBhIGRpZmZlcmVudCBudW1iZXIgb2YgZnJlcXVlbmN5LgoKYGBge3J9CmFsbF9lcXVhbChYLCBZLCBpZ25vcmVfcm93X29yZGVyID0gVFJVRSkKYWxsX2VxdWFsKFgsIFksIGlnbm9yZV9yb3dfb3JkZXIgPSBGQUxTRSkKIyBEb2Vzbid0IHJlcG9ydCByb3dzIGJlaW5nIGRpZmZlcmVudCBvcmRlcgphbGwuZXF1YWwoWCwgWSwgaWdub3JlX3Jvd19vcmRlciA9IFRSVUUpCmFsbC5lcXVhbChYLCBZLCBpZ25vcmVfcm93X29yZGVyID0gRkFMU0UpCiMgRG9lc24ndCByZXBvcnQgcm93cyBiZWluZyBkaWZmZXJlbnQgb3JkZXIKYGBgCgpgc2V0ZXF1YWwoKWAgZG9lcyBub3QgcHJvdmlkZSBjbHVlcyBhYm91dCB3aGF0IGlzIGRpZmZlcmVudCBidXQgVFJVRSAobm8gZGlmZmVyZW5jZXMpIG9yIEZBTFNFIChpbmRpY2F0aW5nIGF0IGxlYXN0IG9uZSBkaWZmZXJlbmNlKS4KCmBgYHtyfQojIFJlcG9ydHMgZmFsc2UgaW5kaWNhdGluZyBhdCBsZWFzdCBvbmUgZGlmZmVyZW5jZQpzZXRlcXVhbChYLCBZKQpgYGAKCmBzZXRkaWZmKClgIHRlbGxzIHVzIHdoYXQgaXMgZGlmZmVyZW50IGFuZCBpcyBkZXBlbmRlbnQgb24gdGhlIG9yZGVyIG9mIHRoZSBvYmplY3RzIGNvbXBhcmVkLCBidXQgcHJpb3JpdGl6ZXMgdGhlIHZhbHVlcyB0aGF0IGFyZSB1bmlxdWUgdG8gZWFjaC4KCmBgYHtyfQojIFRoaXMgcmVwb3J0cyB3aGF0IGlzIHVuaXF1ZSB0byBYCnNldGRpZmYoWCwgWSkgCiMgVGhpcyByZXBvcnRzIHdoYXQgaXMgdW5pcXVlIHRvIFkgLSBub3RoaW5nIGluIHRoaXMgY2FzZQpzZXRkaWZmKFksIFgpIApgYGAKCk5vdyBsZXQncyBtYWtlIGl0IHNvIHRoYXQgb25seSB0aGUgb3JkZXIgaXMgZGlmZmVyZW50OgpgYGB7cn0KWSA8LSB0aWJibGUodGVzdCA9IGMoIkEiLCAiRCIsICJBQyIsICJCIikpClgKWQpgYGAKCk5vdyB0aGF0IHRoZXJlIGFyZSBubyB2YWx1ZXMgdGhhdCBhcmUgdW5pcXVlIHRvIGVpdGhlciBYIG9yIFksIGBhbGxfZXF1YWwoKWAgcmVwb3J0cyB0aGF0IHRoZXJlIGlzIGEgZGlmZmVyZW50IG9yZGVyLiAKYGBge3J9CmFsbF9lcXVhbChYLCBZLCBpZ25vcmVfcm93X29yZGVyID0gVFJVRSkKYWxsX2VxdWFsKFgsIFksIGlnbm9yZV9yb3dfb3JkZXIgPSBGQUxTRSkgIyByZXBvcnRzIGRpZmYgb3JkZXIKYGBgCgoKUmVtZW1iZXIgYHNldGVxdWFsKClgIGlnbm9yZXMgb3JkZXIgYW5kIGdpdmVzIGEgdmFsdWUgb2YgVFJVRSBmb3Igbm8gZGlmZmVyZW5jZXMuCmBgYHtyfQojIEl0IHJlcG9ydHMgbm8gZGlmZmVyZW5jZSEKc2V0ZXF1YWwoWCwgWSkKYGBgCgpgc2V0ZGlmZigpYCBhbHNvIGlnbm9yZXMgb3JkZXIgYW5kIHNob3dzIG5vIGRpZmZlcmVuY2VzLgpgYGB7cn0Kc2V0ZGlmZihYLCBZKSAKYGBgCgpJZiB3ZSBoYXZlIGRpZmZlcmVudCBjb2x1bW4vdmFyaWFibGUgbmFtZXMgdGhpcyBtYWtlcyBjb21wYXJpc29ucyBtb3JlIGNoYWxsZW5naW5nLiBDb2x1bW5zIHdpbGwgYmUgaWRlbnRpZmllZCBmb3IgaGF2aW5nIGRpZmZlcmVudCBuYW1lcy4KYGBge3J9ClggPC0gdGliYmxlKGNvbG5hbWUxID0gYygiQSIsICJCIiwgIkFDIiwgIkQiKSkKWSA8LSB0aWJibGUoY29sbmFtZTIgPSBjKCJBIiwgIkQiLCAiQUciLCAiQiIpKQpgYGAKCmBhbGxfZXF1YWwoKWAgd2lsbCBzaW1wbHkgcmVwb3J0IHRoYXQgY29sIG5hbWVzIGFyZSBkaWZmZXJlbnQKCmBgYHtyfQphbGxfZXF1YWwoWCwgWSwgaWdub3JlX3Jvd19vcmRlciA9IFRSVUUpCmFsbF9lcXVhbChYLCBZLCBpZ25vcmVfcm93X29yZGVyID0gRkFMU0UpCmBgYAoKYHNldGVxYXVsKClgIHdpbGwgcmVwb3J0IGBUUlVFYCBvciBgRkFMU0VgIHRvIGluZGljYXRlIGVpdGhlciBhIGRpZmZlcmVuY2UgaW4gY29sdW1ucyBvciByb3dzCgpgYGB7cn0Kc2V0ZXF1YWwoWCwgWSkKYGBgCgpgc2V0ZGlmZigpYCByZXF1aXJlcyB0aGF0IGNvbHVtbiBuYW1lcyBiZSB0aGUgc2FtZSBzbyB0aGlzIHdpbGwgY2F1c2UgYW4gZXJyb3I6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzZXRkaWZmKFgsIFkpICMgVGhpcyB3aWxsIG5vdCB3b3JrCmBgYAoKPC9kZXRhaWxzPiAKCioqKgoKT0ssIGxldCdzIGtlZXAgZ29pbmcgd2l0aCBvdXIgZGF0YS4KCkhvdyBzaW1pbGFyIGFyZSB0aGUgZ3VpZGVsaW5lcyB0aWJibGUgYW5kIHRoZSBvYnNlcnZlZCBjb25zdW1wdGlvbiB0aWJibGVzPwoKYGBge3J9CgpzZXRlcXVhbChkaXN0aW5jdChkaWV0X2RhdGEsIHJlaV9uYW1lKSwgCiAgICAgICAgICBzZWxlY3QoZ3VpZGVsaW5lcywgZm9vZCkpCmBgYAoKT0ssIGxvb2tzIGxpa2Ugd2UgaGF2ZSBzb21lIGRpZmZlcmVudCB2YWx1ZXMuCgpMZXQncyB1c2UgdGhlIGBzZXRkaWZmYCBmdW5jdGlvbiB0byBnZXQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB3aGF0IGlzIGRpZmZlcmVudCBiZXR3ZWVuIHRoZSB2YWx1ZXMuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzZXRkaWZmKGRpc3RpbmN0KGRpZXRfZGF0YSwgcmVpX25hbWUpLCAKICAgICAgICAgIHNlbGVjdChndWlkZWxpbmVzLCBmb29kKSkKYGBgCgo6KCBUaGF0IHdvbnQgd29yay4gVGhpcyBpcyBiZWNhdXNlIGBzZXRkaWZmKClgIHJlcXVpcmVzIHRoYXQgdGhlIGNvbHVtbiBuYW1lcyBhcmUgdGhlIHNhbWUgaW4gdGhlIG9iamVjdHMgdGhhdCB3ZSBhcmUgY29tcGFyaW5nLgoKCldlIGNhbiB1c2UgdGhlIGByZW5hbWUoKWAgZnVuY3Rpb24gZnJvbSBgZHBseXJgIHRvIGRvIHRoaXMuIFdlIGxpc3QgdGhlIHZhbHVlIHRoYXQgd2Ugd2FudCB0byBjaGFuZ2UgdG8gZmlyc3QuIFdlIGZpbmQgImZvb2QiIG1vcmUgaW50dWl0aXZlIHNvIHdlIGFyZSBnb2luZyB0byBjaGFuZ2UgInJlaV9uYW1lIiB0byAiZm9vZCIgZm9yIHRoZSBgZGlldF9kYXRhYCBhbmQgdGhlIGBzZXBfYWdlX2RpZXRfZGF0YWA6CgpgYGB7cn0KZGlldF9kYXRhICU8PiUKICBkcGx5cjo6cmVuYW1lKGZvb2QgPSByZWlfbmFtZSkKc2VwX2FnZV9kaWV0X2RhdGEgJTw+JQogIGRwbHlyOjpyZW5hbWUoZm9vZCA9IHJlaV9uYW1lKQpgYGAKCgpgYGB7cn0Kc2V0ZGlmZihkaXN0aW5jdChkaWV0X2RhdGEsIGZvb2QpLCAKICAgICAgICAgIHNlbGVjdChndWlkZWxpbmVzLCBmb29kKSkKYGBgCgpHcmVhdCwgbm93IHdlIGtub3cgdGhhdCB0aGUgYGZpYmVyYCB2YWx1ZSBhcHBlYXJzIHRvIGJlIGRpZmZlcmVudCBiZXR3ZWVuIHRoZSB0d28uCgoKQ2hlY2tpbmcgb3VyIG9yaWdpbmFsIGZpbGVzIHdlIGNhbiBzZWUgdGhhdCB0aGUgQnJpdGlzaCBzcGVsbGluZyAiZmlicmUiIGlzIHVzZWQgaW4gdGhlIHRhYmxlIGZyb20gdGhlIGFydGljbGUgKHRoYXQgd2UgdXNlZCB0byBjcmVhdGUgYGd1aWRlbGluZXNgKSwgaW4gY29udHJhc3QgdG8gdGhlIHRoZSBBbWVyaWNhbiBzcGVsbGluZyAiZmliZXIiIHVzZWQgaW4gdGhlIENTViBmaWxlcy4KCkxldCdzIHN0aWNrIHdpdGggdGhlIEFtZXJpY2FuIHNwZWxsaW5nLCBzbyB3ZSB3aWxsIHJlcGxhY2UgYCJmaWJyZSJgIGluIHRoZSBndWlkZWxpbmUgdGliYmxlLgoKYGBge3J9CgpndWlkZWxpbmVzICU8PiUKICBtdXRhdGVfYXQodmFycyhmb29kKSwKICB+IHN0cl9yZXBsYWNlKCAKICBzdHJpbmcgPSAuLCAKICBwYXR0ZXJuID0gImZpYnJlIiwgCiAgcmVwbGFjZW1lbnQgPSAiZmliZXIiKSkKCmd1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gImZpYmVyIikKCmBgYAoKTm93IGxldCdzIGNoZWNrIGFnYWluIHRvIHNlZSB0aGF0IG91ciBmb29kIHZhbHVlcyBtYXRjaCBiZXR3ZWVuIHRoZSBndWlkZWxpbmVzIGFuZCB0aGUgb2JzZXJ2ZWQgY29uc3VtcHRpb24gZGF0YSB0aWJibGVzLgoKYGBge3J9CnNldGRpZmYoc2VsZWN0KGd1aWRlbGluZXMsIGZvb2QpLAogICAgICAgIGRpc3RpbmN0KGRpZXRfZGF0YSwgZm9vZCkpCgpzZXRkaWZmKHNlbGVjdChndWlkZWxpbmVzLCBmb29kKSwKICAgICAgICBkaXN0aW5jdChzZXBfYWdlX2RpZXRfZGF0YSwgZm9vZCkpCmBgYAoKR3JlYXQhICBUaGVyZSBhcmUgbm8gZGlmZmVyZW5jZXMgOikKCiMjIyBKb2luaW5nIGRhdGEKCk5vdyB3ZSBjYW4gcHV0IG91ciBndWlkZWxpbmUgZGF0YSB0b2dldGhlciB3aXRoIHRoZSBgZGlldF9kYXRhYCBhbmQgdGhlIGBzZXBfYWdlX2RpZXRfZGF0YWAuCgpSZW1lbWJlciB0aGF0IHRoZSBgZm9vZGAgZGF0YSBpbiBvdXIgYGd1aWRlbGluZXNgIHRpYmJsZSBpcyBub3QgbmVjZXNzYXJpbHkgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhhdCBvZiB0aGUgY29uc3VtcHRpb24gZGF0YSB0aWJibGVzLiBUaHVzIHRoaXMgY291bGQgYmUgYSBwcm9ibGVtIGlmIHdlIGRlY2lkZWQgdG8gZXhwYW5kIHRoZSBgZ3VpZGVsaW5lc2Agcm93cyAodG8gcmVwZWF0IGZvciB0aGUgbnVtYmVyIG9mIGZydWl0IG9ic2VydmF0aW9ucyBldGMuKSBhbmQgYWRkIHRoZW0gdG8gb3VyIG9ic2VydmVkIGNvbnN1bXB0aW9uIHRpYmJsZXMgYnkgYmluZGluZyB0aGVtIHRvZ2V0aGVyIGJ5IGNvbHVtbi4gCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXR3aWR0aCA9ICI1MCUiLCBmaWcuYWxpZ249ICJjZW50ZXIifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCJiaW5kLnBuZyIpKQpgYGAKCiMjIyMgW1tzb3VyY2VdXShodHRwczovL3JzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE1LzAyL2RhdGEtd3JhbmdsaW5nLWNoZWF0c2hlZXQucGRmKQoKSW4gdGhhdCBjYXNlIHdlIGNvdWxkIHVzZSB0aGUgYGFycmFuZ2UoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYCB0byBzb3J0IHRoZSBkYXRhIGFscGhhYmV0aWNhbGx5LgoKSG93ZXZlciwgd2Ugd2lsbCBpbnN0ZWFkIHVzZSBhIGpvaW5pbmcgZnVuY3Rpb24gb2YgYGRwbHlyYC4gVGhlc2UgZnVuY3Rpb25zIGNvbWJpbmUgdGhlIGRhdGEgdG9nZXRoZXIgYmFzZWQgb24gKipjb21tb24gdmFsdWVzKiogYW5kIGRvbid0IHJlcXVpcmUgdGhlIHJvd3MgdG8gYmUgaW4gdGhlIHNhbWUgb3JkZXIuIFRoZXJlIGFyZSBhIHZhcmlldHkgb2Ygb3B0aW9ucy4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dHdpZHRoID0gIjUwJSIsIGZpZy5hbGlnbj0gImNlbnRlciJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsImpvaW4ucG5nIikpCmBgYAoKIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vcnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDIvZGF0YS13cmFuZ2xpbmctY2hlYXRzaGVldC5wZGYpCgoKSW4gb3VyIGNhc2Ugd2Ugd291bGQgbGlrZSB0byByZXRhaW4gYWxsIG9mIHRoZSB2YWx1ZXMgb2YgYGRpZXRfZGF0YWAgYW5kIGBzZXBfYWdlX2RpZXRfZGF0YWAuIFdlIHdvdWxkIGxpa2UgdG8gYWRkIG5ldyBjb2x1bW5zIG9mIHZhbHVlcyB0byB0aGVzZSB0aWJibGVzIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgZ3VpZGVsaW5lIGluZm9ybWF0aW9uIGFib3V0IGFtb3VudHMgb2YgY29uc3VtcHRpb24gZm9yIGVhY2ggZm9vZCB0eXBlIGluIHRoZSBgZ3VpZGVsaW5lc2AgdGliYmxlLiBXZSBzaG91bGRuJ3QgaGF2ZSBhbnkgdmFsdWVzIG9mIGBmb29kYCBpbiBgZ3VpZGVsaW5lc2AgdGhhdCBkb24ndCBtYXRjaCwgc28gd2Ugd2lsbCBub3QgZ2V0IGFueSBgTkFgIHZhbHVlcy4gVGhlcmVmb3JlLCBpbiBvdXIgY2FzZSBhbnkgb2YgdGhlIG11dGF0aW5nIGpvaW4gZnVuY3Rpb25zIHNob3VsZCByZXN1bHQgaW4gdGhlIHNhbWUgb3V0cHV0LgoKSXQncyBpbXBvcnRhbnQgdG8gY2hlY2sgaWYgd2UgaGF2ZSBhbnkgb3ZlcmxhcHBpbmcgdmFyaWFibGUgbmFtZXMgYmVmb3JlIHdlIGpvaW4gdGhlIGRhdGEuIE90aGVyd2lzZSwgdGhlc2UgY29sdW1ucyB3aWxsIGVpdGhlciBiZSB1c2VkIHRvIGlkZW50aWZ5IHdoaWNoIHJvd3MgdG8gam9pbiwgb3IgbmV3IGNvcGllcyBvZiB0aGUgY29sdW1ucywgd2l0aCBhIGRlZmF1bHQgbmFtZSB0byBkaXN0aW5ndWlzaCB0aGUgY29sdW1ucyBvZiBvbmUgZGF0YSBzZXQgZnJvbSB0aG9zZSBvZiB0aGUgb3RoZXIsIHdpbGwgYmUgY3JlYXRlZC4gV2UgY2FuIHVzZSB0aGUgYmFzZSBSIGZ1bmN0aW9uIGBuYW1lcygpYCAgYW5kIHRoZSBgaW50ZXJzZWN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gaWRlbnRpZnkgd2hpY2ggY29sdW1uIG5hbWVzIGFyZSBjb21tb24gdG8gb3VyIHR3byBkYXRhIHNldHMuCgpgYGB7cn0KZHBseXI6OmludGVyc2VjdChuYW1lcyhkaWV0X2RhdGEpLCAKICAgICAgICAgIG5hbWVzKGd1aWRlbGluZXMpKQpgYGAKClNvIGl0IGxvb2tzIGxpa2UgdGhlIGAidXBwZXIiYCAsIGAibG93ZXIiYCBhbmQgYCJ1bml0ImAgdmFyaWFibGUgbmFtZXMgYXJlIG92ZXJsYXBwaW5nLiBUaGVyZWZvcmUsIHRvIGRpc3Rpbmd1aXNoIHRoZSBuYW1lcyBsYXRlciB3ZSB3aWxsIHJlbmFtZSB0aGUgZ3VpZGVsaW5lIGAidXBwZXIiYCAsIGAibG93ZXIiYCBhbmQgYCJ1bml0ImAgdmFyaWFibGVzLgoKV2Ugd2lsbCBhZ2FpbiB1c2UgdGhlIGByZW5hbWVgIGZ1bmN0aW9uIGZyb20gdGhlIGBkcGx5cmAgcGFja2FnZS4gV2UgY2FuIGxpc3QgbXVsdGlwbGUgdmFyaWFibGVzIHRvIHJlbmFtZSBhbmQgc2VwYXJhdGUgZWFjaCB3aXRoIGEgY29tbWEuIFdlIG5lZWQgdG8gbGlzdCB0aGUgbmV3IG5hbWVzIGZpcnN0LgoKYGBge3J9Cmd1aWRlbGluZXMgJTw+JQogIHJlbmFtZSh1cHBlcl9vcHRpbWFsID0gdXBwZXIsIAogICAgICAgICBsb3dlcl9vcHRpbWFsID0gbG93ZXIsCiAgICAgICAgICB1bml0X29wdGltYWwgPSB1bml0KQoKZ3VpZGVsaW5lcwpgYGAKCkl0IGlzIGFsc28gYSBnb29kIGlkZWEgdG8gY2hlY2sgb3VyIHVuaXRzIHRvIG1ha2Ugc3VyZSB0aGV5IGFyZSB0aGUgc2FtZSBmb3IgYm90aCBgZ3VpZGVsaW5lc2AgYW5kIHRoZSBvYnNlcnZlZCBjb25zdW1wdGlvbiB0aWJibGVzKGBkaWV0X2FuZF9ndWlkZWxpbmVzYCBhbmQgYGFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lc2ApLgoKTGV0J3MgdGFrZSBhIGxvb2sgd2l0aCB0aGUgYGNvdW50KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFdlIHdpbGwgYWxzbyB1c2UgdGhlIGBiaW5kX2NvbHMoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYCB0byBwdXQgdGhlIGRhdGEgdG9nZXRoZXIgc28gdGhhdCB3ZSBjYW4gc2VlIGl0IGVhc2lseS4KCmBgYHtyfQoKZHBseXI6OmJpbmRfY29scyhjb3VudChkaWV0X2RhdGEsIHVuaXQsIGZvb2QpLCAKICAgICAgIGNvdW50KHNlcF9hZ2VfZGlldF9kYXRhLHVuaXQsZm9vZCksCiAgICAgICBjb3VudChndWlkZWxpbmVzLCB1bml0X29wdGltYWwsIGZvb2QpKQpgYGAKCldlIGNhbiBzZWUgdGhhdCB0aGUgb25seSBwb3RlbnRpYWwgaXNzdWUgaXMgdGhlIGBzZWFmb29kIG9tZWdhLTMgZmF0dHkgYWNpZHNgIGRhdGEgd2hpY2ggaXMgaW4gZy9kYXkgZm9yIHRoZSBvYnNlcnZlZCBkYXRhKGBkaWV0X2RhdGFgIGFuZCBgYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzYCksIGJ1dCBpbiBtZy9kYXkgaW4gdGhlIGBndWlkZWxpbmVzYCBkYXRhLgoKV2UgY2FuIGFjY291bnQgZm9yIHRoaXMgYnkgZGl2aWRpbmcgdGhlIGBndWlkZWxpbmVzYCBgc2VhZm9vZCBvbWVnYS0zIGZhdHR5IGFjaWRzIGRhdGFgIGJ5IDEwMDAgdG8gY29udmVydCBpdCB0byBncmFtcyBmcm9tIG1pbGxpZ3JhbXMuCgpUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgaWZfZWxzZSgpYCBmdW5jdGlvbiBpbiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGlzIGFsbG93cyB1cyB0byBzcGVjaWZ5IGEgY29uZGl0aW9uIChpbiB0aGlzIGNhc2UgaWYgdGhlIHVuaXQgaXMgYCJtZyJgKSwgYXMgd2VsbCBhcyB2YWx1ZXMgaWYgdGhpcyBpcyBjb25kaXRpb24gaXMgbWV0ICh0cnVlKSwgb3IgaWYgdGhlIGNvbmRpdGlvbiBpcyBub3QgbWV0IChmYWxzZSkuIAoKSW4gdGhlIGZvbGxvd2luZyB3ZSBtdXRhdGUgdGhlIHZhbHVlcyBpbiBlYWNoIG9mIHRoZSBndWlkZWxpbmUgbnVtZXJpYyBjb2x1bW5zIChgbG93ZXJgLCBgb3B0aW1hbGAgYW5kIGB1cHBlcmApIG9uZSBhdCBhIHRpbWUuIFdoZW4gd2UgcmVmZXIgdG8gYGxvd2VyYCBmb3IgZXhhbXBsZSB3ZSByZWZlciB0byB0aGUgdmFsdWVzIGluIHRoZSBjb2x1bW4vdmFyaWFibGUuIFNvIGlmIHRoZSBjb25kaXRpb24gaXMgbm90IG1ldCwgdGhlbiB0aGUgb3JpZ2luYWwgdmFsdWUgaXMgcmV0YWluZWQuIFdlIHdpbGwgYWxzbyByZXBsYWNlIGAibWciYCB3aXRoIGAiZyJgIGFmdGVyIGV2ZXJ5dGhpbmcgaXMgY29udmVydGVkIHRvIGdyYW1zLgoKCgpgYGB7cn0KCmd1aWRlbGluZXMgJTw+JSBtdXRhdGUobG93ZXJfb3B0aW1hbCA9IGRwbHlyOjppZl9lbHNlKAogIGNvbmRpdGlvbiA9IHVuaXRfb3B0aW1hbCA9PSAibWciLCAKICB0cnVlID0gbG93ZXJfb3B0aW1hbC8xMDAwLCAKICBmYWxzZSA9IGxvd2VyX29wdGltYWwpKQoKZ3VpZGVsaW5lcyAlPD4lIG11dGF0ZShvcHRpbWFsID0gaWZfZWxzZSgKICBjb25kaXRpb24gPSB1bml0X29wdGltYWwgPT0gIm1nIiwgCiAgdHJ1ZSA9IG9wdGltYWwvMTAwMCwgCiAgZmFsc2UgPSBvcHRpbWFsKSkKCmd1aWRlbGluZXMgJTw+JSBtdXRhdGUodXBwZXJfb3B0aW1hbCA9IGlmX2Vsc2UoCiAgY29uZGl0aW9uID0gdW5pdF9vcHRpbWFsID09ICJtZyIsIAogIHRydWUgPSB1cHBlcl9vcHRpbWFsLzEwMDAsIAogIGZhbHNlID0gdXBwZXJfb3B0aW1hbCkpCgoKZ3VpZGVsaW5lcyAlPD4lIG11dGF0ZSh1bml0X29wdGltYWwgPSBpZl9lbHNlKAogIGNvbmRpdGlvbiA9IHVuaXRfb3B0aW1hbCA9PSAibWciLCAKICB0cnVlID0gImciLCAKICBmYWxzZSA9IHVuaXRfb3B0aW1hbCkpCgpndWlkZWxpbmVzCgoKYGBgCgoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgYSBjb3VwbGUgb2Ygb3RoZXIgd2F5cyB0byBkbyB0aGlzOiA8L3N1bW1hcnk+CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQojIEFub3RoZXIgcG9zc2libGUgd2F5IHdpdGggZHBseXI6OmNhc2Vfd2hlbigpOgogZ3VpZGVsaW5lcyAlPD4lCiAgIG11dGF0ZShsb3dlcl9vcHRpbWFsID0gY2FzZV93aGVuKAogICB1bml0X29wdGltYWwgPT0gIm1nIiB+IGxvd2VyX29wdGltYWwvMTAwMCwKICAgdW5pdF9vcHRpbWFsICE9ICJtZyIgfiBsb3dlcl9vcHRpbWFsKSkKCiMgT3IgY291bGQgdXNlIHRoaXM6Cmd1aWRlbGluZXMgJTw+JQogIG11dGF0ZV9hdCh2YXJzKHVuaXRfb3B0aW1hbCksCiAgIH5zdHJfcmVwbGFjZSggCiAgIHN0cmluZyA9IC4sIAogICBwYXR0ZXJuID0gIm1nIiwgCiAgIHJlcGxhY2VtZW50ID0gImciKSkKCmBgYAoKPC9kZXRhaWxzPgoKKioqCgoKCkluIGNvbnRyYXN0IHdlIGNvdWxkIGhhdmUgY2hhbmdlZCBvciBtdXRhdGVkIHRoZSB2YWx1ZXMgZm9yIGBsb3dlcl9vcHRpbWFsYCwgYG9wdGltYWxgLCBgdXBwZXJfb3B0aW1hbGAgYWxsIGF0IG9uY2UgbGlrZSB0aGlzIHVzaW5nIHRoZSBgZnVucygpYCBhcmd1bWVudCBpbiBgbXV0YXRlX2F0KClgIG9mIGBkcGx5cmAuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQoKZ3VpZGVsaW5lc1tzdHJfd2hpY2goc3RyaW5nID0gZ3VpZGVsaW5lc1tbImZvb2QiXV0sIAogICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAic2VhZm9vZCBvbWVnYS0zIGZhdHR5IGFjaWRzIiksXSA8LSBndWlkZWxpbmVzICU+JSAKICAgIGZpbHRlcihmb29kID09ICJzZWFmb29kIG9tZWdhLTMgZmF0dHkgYWNpZHMiKSAlPiUKICAgIG11dGF0ZV9hdCh2YXJzKGxvd2VyX29wdGltYWw6dXBwZXJfb3B0aW1hbCksIGZ1bnMoLi8xMDAwKSkKCmBgYAoKCk5vdyB3ZSBhcmUgcmVhZHkgdG8gam9pbiB0aGUgZGF0YSEKCkFnYWluLCB3ZSB3b3VsZCBsaWtlIHRvIGFkZCBuZXcgY29sdW1ucyBvZiB2YWx1ZXMgdG8gYGRpZXRfZGF0YWAgYW5kIGBhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXNgIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgZ3VpZGVsaW5lIGluZm9ybWF0aW9uIGFib3V0IGFtb3VudHMgb2YgY29uc3VtcHRpb24gZm9yIGVhY2ggZm9vZCB0eXBlIGluIHRoZSBgZ3VpZGVsaW5lc2AgdGliYmxlLiBTbyB3ZSB3aWxsIGpvaW4gdGhlIGRhdGEgYmFzZWQgb24gdGhlIGBmb29kYCB2YXJpYWJsZSB2YWx1ZXMuIFdlIHdpbGwgdXNlIHRoZSBgZnVsbF9qb2luKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyA8LSBkaWV0X2RhdGEgJT4lCiAgZHBseXI6OmZ1bGxfam9pbihndWlkZWxpbmVzLCBieSA9ICJmb29kIiApCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgPC0gc2VwX2FnZV9kaWV0X2RhdGEgJT4lCiAgZnVsbF9qb2luKGd1aWRlbGluZXMsIGJ5ID0gImZvb2QiICkKCmdsaW1wc2UoZGlldF9hbmRfZ3VpZGVsaW5lcykKZ2xpbXBzZShhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMpCgpgYGAKCkl0J3MgYWx3YXlzIGEgZ29vZCBpZGVhIHRvIGNoZWNrIHRoYXQgdGhlIHZhbHVlcyBhcmUgd2hhdCB5b3UgZXhwZWN0IGFmdGVyIG1lcmdpbmcuIAoKYGBge3J9CgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGNvdW50KGZvb2QsIG9wdGltYWwpCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgY291bnQoZm9vZCwgb3B0aW1hbCkKCiNGb3IgZWFzeSBjb21wYXJpc29uIHdlIHdpbGwgYXJyYW5nZSBieSBmb29kIGFscGhhYmV0aWNhbGx5CmFycmFuZ2UoZ3VpZGVsaW5lcywgZm9vZCkKYGBgCgpMb29rcyBnb29kIQogCiAKIyMjIENhbGN1bGF0aW5nIHJlbGF0aXZlIGNvbnN1bXB0aW9uIAoKUmVjYWxsIHRoYXQgb3VyIGFpbSBpcyB0byBjb21wYXJlIHRoZSBjb25zdW1wdGlvbiByYXRlcyBvZiB0aGVzZSBkaWV0YXJ5IGZhY3RvcnMgYnkgZGlmZmVyZW50IGdyb3VwcyBvZiBwZW9wbGUsIGFuZCBpZGVhbGx5LCB0byBmYWNpbGl0YXRlIGNyb3NzLWZhY3RvciBjb21wYXJpc29ucywgd2Ugd2FudCB0byBjb25zaWRlciBjb25zdW1wdGlvbiByYXRlcyByZWxhdGl2ZSB0byB0aGUgb3B0aW1hbCBndWlkZWxpbmVzLgoKVG8gZG8gdGhpcywgbGV0J3MgY2FsY3VsYXRlIHZhbHVlcyBvZiBjb25zdW1wdGlvbiB0aGF0IGFyZSByZWxhdGl2ZSB0byB0aGUgc3VnZ2VzdGVkIGd1aWRlbGluZXMuCgpUaGVyZSBhcmUgYSBmZXcgYXBwcm9hY2hlcyB3ZSBjb3VsZCB0YWtlLiBPbmUgaXMgdG8gY2FsY3VsYXRlIGEgYCJwZXJjZW50YWdlIG9mIG9wdGltYWwgY29uc3VtcHRpb24iYCB1c2luZyB0aGUgbWVhbiB2YWx1ZSBmb3IgZWFjaCBvYnNlcnZlZCBmYWN0b3IgcmVsYXRpdmUgdG8gaXRzIG9wdGltYWwgdmFsdWUuIFRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmBwYWNrYWdlLiBUaGlzIHdpbGwgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBgUmVsYXRpdmVfUGVyY2VudGAgdGhhdCB3aWxsIGJlIGVxdWFsIHRvIHRoZSByYXRpbyBvZiB0aGUgYG1lYW5gIHZhbHVlIGFuZCB0aGUgYG9wdGltYWxgIHZhbHVlLCBtdWx0aXBsaWVkIGJ5IDEwMCwgdG8gY3JlYXRlIGEgcGVyY2VudGFnZSByZWxhdGl2ZSB0byB0aGUgb3B0aW1hbCBhbW91bnQgc3VnZ2VzdGVkLgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZShSZWxhdGl2ZV9QZXJjZW50ID0gKG1lYW4vb3B0aW1hbCkqMTAwKQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUKIG11dGF0ZShSZWxhdGl2ZV9QZXJjZW50ID0gKG1lYW4vb3B0aW1hbCkqMTAwKQpgYGAKCkFub3RoZXIgb3B0aW9uIGlzIHRvIGluY29ycG9yYXRlIHRoZSByYW5nZSBvZiBvcHRpbWFsIGludGFrZXMgYW5kIHRoZSBkaXJlY3Rpb24gdGhhdCBpcyBhc3NvY2lhdGVkIHdpdGggaGVhbHRoIHJpc2suIElmIHRoZSBkaXJlY3Rpb24gb2YgcmlzayBpcyBgaGlnaGAgYW5kIHRoZSBjb25zdW1wdGlvbiB3YXMgZ3JlYXRlciB0aGFuIHRoZSBgb3B0aW1hbGAgbWVhbiB2YWx1ZSwgdGhhbiB0aGUgcGVyY2VudGFnZSBpcyBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoZSBgdXBwZXJfb3B0aW1hbGAgdmFsdWUsIHdoaWxlIGlmIHRoZSBkaXJlY3Rpb24gb2YgcmlzayBpcyBgbG93YCBhbmQgdGhlIGNvbnN1bXB0aW9uIGlzIGxlc3MgdGhhbiB0aGUgYG9wdGltYWxgIG1lYW4gdmFsdWUsIHRoZW4gdGhlIHBlcmNlbnRhZ2UgaXMgY2FsY3VsYXRlZCBiYXNlZCBvbiB0aGUgYGxvd2VyX29wdGltYWxgIHZhbHVlLiBXZSB3aWxsIHVzZSB0aGUgYGNhc2Vfd2hlbigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGRvIHRoaXMuIFRoaXMgYWxsb3dzIHVzIHRvIHNwZWNpZnkgdmFsdWVzIChpbmRpY2F0ZWQgb24gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIGB+YHN5bWJvbCkgYmFzZWQgb24gc3BlY2lmaWMgY29uZGl0aW9ucyAoaW5kaWNhdGVkIG9uIHRoZSBsZWZ0IHNpZGUgb2YgdGhlIGB+YCBzeW1ib2wpLiBXZSBjYW4gc3BlY2lmeSBtdWx0aXBsZSBjb25kaXRpb25zIHVzaW5nIHRoZSBgJmAgc3ltYm9sLgoKYGBge3J9CgpkaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUKICBtdXRhdGUocmFuZ2VfcGVyY2VudCA9IGNhc2Vfd2hlbigKICBkaXJlY3Rpb24gPT0gImhpZ2giIH4gIChtZWFuL3VwcGVyX29wdGltYWwpKjEwMCwKICBkaXJlY3Rpb24gPT0gImxvdyIgIH4gIChtZWFuL2xvd2VyX29wdGltYWwpKjEwMCkpCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZShyYW5nZV9wZXJjZW50ID0gY2FzZV93aGVuKAogIGRpcmVjdGlvbiA9PSAiaGlnaCIgfiAgKG1lYW4vdXBwZXJfb3B0aW1hbCkqMTAwLAogIGRpcmVjdGlvbiA9PSAibG93IiAgfiAgKG1lYW4vbG93ZXJfb3B0aW1hbCkqMTAwKSkKCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUKICBtdXRhdGUocGVyY2VudF9vdmVyX3VuZGVyID0gY2FzZV93aGVuKAogIGRpcmVjdGlvbiA9PSAiaGlnaCIgJiBtZWFuID4gdXBwZXJfb3B0aW1hbCB+IAogICAgKChtZWFuLXVwcGVyX29wdGltYWwpL3VwcGVyX29wdGltYWwpKjEwMCwKICBkaXJlY3Rpb24gPT0gImhpZ2giICYgbWVhbiA8PSB1cHBlcl9vcHRpbWFsIH4gMCwKICBkaXJlY3Rpb24gPT0gImxvdyIgICYgbWVhbiA+PSBsb3dlcl9vcHRpbWFsIH4gMCwKICBkaXJlY3Rpb24gPT0gImxvdyIgICYgbWVhbiA8IGxvd2VyX29wdGltYWwgfiAKICAgICgobG93ZXJfb3B0aW1hbC1tZWFuKS9sb3dlcl9vcHRpbWFsKSotMTAwKSkKCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZShwZXJjZW50X292ZXJfdW5kZXIgPSBjYXNlX3doZW4oCiAgZGlyZWN0aW9uID09ICJoaWdoIiAmIG1lYW4gPiB1cHBlcl9vcHRpbWFsIH4gIAogICAgKChtZWFuLXVwcGVyX29wdGltYWwpL3VwcGVyX29wdGltYWwpKjEwMCwKICBkaXJlY3Rpb24gPT0gImhpZ2giICYgbWVhbiA8PSB1cHBlcl9vcHRpbWFsIH4gMCwKICBkaXJlY3Rpb24gPT0gImxvdyIgICYgbWVhbiA+PSBsb3dlcl9vcHRpbWFsIH4gMCwKICBkaXJlY3Rpb24gPT0gImxvdyIgICYgbWVhbiA8IGxvd2VyX29wdGltYWwgfiAKICAgICgobG93ZXJfb3B0aW1hbC1tZWFuKS9sb3dlcl9vcHRpbWFsKSotMTAwKSkKCmBgYAoKQW5vdGhlciBvcHRpb24gaXMgdG8gY3JlYXRlIGEgYmluYXJ5IG91dGNvbWUgaW5kaWNhdGluZyB3aGV0aGVyIG9wdGltYWwgY29uc3VtcHRpb24gd2FzIGFjaGlldmVkIG9yIG5vdC4KCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPD4lCiAgbXV0YXRlKG9wdF9hY2hpZXZlZCA9IGlmX2Vsc2UoCiAgICBjb25kaXRpb24gPSBkaXJlY3Rpb24gPT0gImxvdyIgJiBtZWFuID4gbG93ZXJfb3B0aW1hbCB8CiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPT0gImhpZ2giICYgbWVhbiA8IHVwcGVyX29wdGltYWwsIAogICAgdHJ1ZSA9ICJZZXMiLAogICAgZmFsc2UgPSAiTm8iKSkKCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPD4lCiAgbXV0YXRlKG9wdF9hY2hpZXZlZCA9IGlmX2Vsc2UoCiAgICBjb25kaXRpb24gPSBkaXJlY3Rpb24gPT0gImxvdyIgJiBtZWFuID4gbG93ZXJfb3B0aW1hbCB8CiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPT0gImhpZ2giICYgbWVhbiA8IHVwcGVyX29wdGltYWwsIAogICAgdHJ1ZSA9ICJZZXMiLAogICAgZmFsc2UgPSAiTm8iKSkKCmdsaW1wc2UoZGlldF9hbmRfZ3VpZGVsaW5lcykKZ2xpbXBzZShhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMpCmBgYAoKT25lIGxhc3QgdGhpbmcgdGhhdCBjYW4gYmUgdXNlZnVsIHdpdGggZGF0YSB3cmFuZ2xpbmcgaXMgdG8gKipyZXNoYXBlKiogdGhlIGRhdGEgaW50byB3aGF0IGlzIGNhbGxlZCB0aGUgKipsb25nKiogZm9ybWF0LiBUaGlzIGlzIHZlcnkgdXNlZnVsIGZvciBjcmVhdGluZyB2aXN1YWxpemF0aW9ucyB3aXRoIGEgcG93ZXJmdWwgYW5kIGZsZXhpYmxlIHBhY2thZ2UgY2FsbGVkIGBnZ3Bsb3QyYC4KClRvIGNvZXJjZSBhbiBvYmplY3QgaW50byBsb25nIGZvcm1hdCwgd2UgY3JlYXRlICoqbW9yZSByb3dzIGFuZCBmZXdlciBjb2x1bW5zKiouIEZvciBhIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhpcywgcGxlYXNlIHNlZSB0aGlzIFtjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWhlYWx0aGV4cGVuZGl0dXJlL29jcy1oZWFsdGhleHBlbmRpdHVyZS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LgoKV2Ugd291bGQgbGlrZSB0byBwdXQgdG9nZXRoZXIgdGhlIGRpZmZlcmVudCB0eXBlcyBvZiBwZXJjZW50YWdlcyBvZiB0aGUgb3B0aW1hbCBpbnRha2UgdGhhdCB3ZSBqdXN0IGNhbGN1bGF0ZWQuCgpUbyBnZXQgb3VyIGRhdGEgaW4gbG9uZyBmb3JtYXQgd2UgY2FuIHVzZSB0aGUgYHBpdm90X2xvbmdlcigpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlLiBXZSB3aWxsIGFsc28gc2hvdyBob3cgdGhpcyB3b3VsZCBiZSBkb25lIHdpdGggdGhlIG9sZGVyIHZlcnNpb24gb2YgdGhpcyBmdW5jdGlvbiwgY2FsbGVkIGBnYXRoZXIoKWAuIAoKRm9yIGBwaXZvdF9sb25nZXIoKWAsIHdlIHdpbGwgbGlzdCB0aGUgY29sdW1ucyB0aGF0IHdlIHdhbnQgdG8gY29tZSB0b2dldGhlciBpbnRvIHRoZSBsb25nZXIgZm9ybWF0IHVzaW5nIHRoZSBgY29sc2AgYXJndW1lbnQuIEZvciBgZ2F0aGVyKClgIHdlIHdvdWxkIHNpbXBseSBsaXN0IHRoZSB2YXJpYWJsZXMgdGhhdCB3ZSB3aXNoIHRvIGNvbnNvbGlkYXRlLiBUaGUgYG5hbWVzX3RvYCBhcmd1bWVudCBpbmRpY2F0ZXMgdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlIHRoYXQgd2lsbCBpbmNsdWRlIHRoZSBjaGFyYWN0ZXIgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHZhbHVlcyB0aGF0IHdlIGFyZSBjb25zb2xpZGF0aW5nLCBpLmUuLCB0aGlzIHZhcmlhYmxlIGNvbnRhaW5zIHRoZSBuYW1lcyBvZiB0aGUgY29sdW1ucyB0aGF0IHdlIGFyZSBicmluZ2luZyB0b2dldGhlci4gVGhpcyBpcyBlcXVpdmFsZW50IHRvIHRoZSBga2V5YCBhcmd1bWVudCBpbiBgZ2F0aGVyKClgLiBUaGUgYHZhbHVlc190b2AgaXMgdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiB0aGF0IHdpbGwgY29udGFpbiB0aGUgdmFsdWVzIG9mIHRoZSBjb2x1bW5zIHdlIGFyZSBjb25zb2xpZGF0aW5nLiBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gdGhlIGB2YWx1ZWAgYXJndW1lbnQgaW4gYGdhdGhlcigpYC4gV2UgY2FuIHVzZSBgY29udGFpbnMoKWAgb2YgdGhlIGB0aWR5cmAgcGFja2FnZSB0byBsb29rIGF0IHRoZSB2YXJpYWJsZXMgd2l0aCBuYW1lcyB0aGF0IGNvbnRhaW4gYCJwZXJjZW50ImAgLgoKV2Ugd291bGQgZ2V0IGFuIGlkZW50aWNhbCBvdXRwdXQgZnJvbSB0aGUgbWV0aG9kcy4gV2UgY2FuIGNoZWNrIHRoYXQgd2l0aCBgc2V0ZXF1YWwoKWAuCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nIDwtIGRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCnBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoInBlcmNlbnQiKSwgCiAgICAgICAgIG5hbWVzX3RvID0gInBlcmNlbnRfdHlwZSIsIAogICAgICAgIHZhbHVlc190byA9ICJwZXJjZW50IikKCmRpZXRfYW5kX2d1aWRlbGluZXNfbG9uZzIgPC0gZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKZ2F0aGVyKGNvbnRhaW5zKCJwZXJjZW50IiksCiAgICAgICBrZXkgPSBwZXJjZW50X3R5cGUsIAogICAgIHZhbHVlID0gcGVyY2VudCkKCnNldGVxdWFsKGRpZXRfYW5kX2d1aWRlbGluZXNfbG9uZywgZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nMikKYGBgCgpMZXQncyBkbyB0aGUgc2FtZSBmb3IgdGhlIGFnZSBzZXBhcmF0ZWQgZGF0YS4KCmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXNfbG9uZyA8LSBhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCnBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoInBlcmNlbnQiKSwgCiAgICAgICAgIG5hbWVzX3RvID0gInBlcmNlbnRfdHlwZSIsIAogICAgICAgIHZhbHVlc190byA9ICJwZXJjZW50IikKYGBgCgpXZSBub3cgaGF2ZSB0aGUgbWFpbiB2YXJpYWJsZXMgYW5kIGRhdGEgZm9ybWF0cyB0aGF0IHdlIG5lZWQgdG8gcHJvY2VlZCB3aXRoIHRoZSBuZXh0IHN0ZXBzIG9mIG91ciBhbmFseXNpcywgaW5jbHVkaW5nIGRhdGEgZXhwbG9yYXRpb24gYW5kIGV2ZW50dWFsbHksIG1vZGVsaW5nLgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Kc2F2ZShhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMsIGFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nLCBkaWV0X2FuZF9ndWlkZWxpbmVzLCBzZXBfYWdlX2RpZXRfZGF0YSwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkKYGBgCgojIyAqKkRhdGEgRXhwbG9yYXRpb24qKgoqKioKIAojIyMgRXhwbG9yaW5nIGFnZSBjb2xsYXBzZWQgZGF0YQoKYGBge3IsIGVjaG8gPSBGQUxTRX0KIyBGb3IgaW5zdHJ1Y3RvcnMgd2hvIHdpc2ggdG8gc3RhcnQgYXQgdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIGxvYWQgdGhlIGRhdGEKbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkX2RhdGEucmRhIikpCmBgYAoKTGV0J3Mgc3RhcnQgYnkgdGFraW5nIGEgbG9vayBhdCB0aGUgIHBlcmNlbnQgb2YgY29uc3VtcHRpb24sIGFjcm9zcyBhbGwgZGlldGFyeSBmYWN0b3JzLiBBZ2FpbiB3ZSB3aWxsIHVzZSB0aGUgYmFzZSBSIGBzdW1tYXJ5KClgIGZ1bmN0aW9uOgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgc2VsZWN0KFJlbGF0aXZlX1BlcmNlbnQpICU+JQogIHN1bW1hcnkoKQpgYGAKCldvdyEgU29tZSBvZiB0aGUgdmFsdWVzIGFyZSBuZWFybHkgemVybywgc3VnZ2VzdGluZyB0aGF0IHNvbWUgcGVvcGxlIGFyZSBjb25zdW1pbmcgYmFzaWNhbGx5IHplcm8gcGVyY2VudCBvZiB3aGF0IGlzIHN1Z2dlc3RlZCBmb3Igb3B0aW1hbCBoZWFsdGguIE9uIHRoZSBvdGhlciBoYW5kLCBmb3Igc29tZSBkaWV0YXJ5IGZhY3RvcnMgcGVvcGxlIGFyZSBjb25zdW1pbmcgb3ZlciA3LDAwMCBwZXJjZW50IHdoYXQgaXMgc3VnZ2VzdGVkISAKClRoaXMgaXMgd2h5IGl0IGlzIGltcG9ydGFudCB0byBsb29rIGF0IHRoZSBkaXJlY3Rpb24gb2YgY29uc3VtcHRpb24gdGhhdCBjb3VsZCBiZSBoYXJtZnVsLiBGb3IgZXhhbXBsZSBpZiB0aGVyZSBpcyBhIHBvcHVsYXRpb24gdGhhdCBjb25zdW1lcyBsYXJnZSBhbW91bnRzIG9mIHZlZ2V0YWJsZXMgdGhpcyBjb3VsZCBiZSBhIGdvb2QgdGhpbmcsIGJ1dCBpZiB0aGVyZSBpcyBhIHBvcHVsYXRpb24gY29uc3VtaW5nIGxhcmdlIGFtb3VudHMgb2Ygc29kaXVtIHRoaXMgd291bGQgYmUgYSBiYWQgdGhpbmcuIAoKTGV0J3MgdGFrZSBhIGxvb2sgdG8gc2VlIHdoYXQgZGlldGFyeSBmYWN0b3JzIGFyZSBhdCB0aGUgZXh0cmVtZXMgYnkgYXJyYW5naW5nIHRoZSBkYXRhIHVzaW5nIHRoZSBgYXJyYW5nZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBXZSBjYW4gYXJyYW5nZSBieSBzbWFsbGVzdCB0byBsYXJnZXN0IHVzaW5nIHRoZSBkZWZhdWx0IGFuZCB3ZSBjYW4gYXJyYW5nZSBsYXJnZXN0IHRvIHNtYWxsZXN0IHVzaW5nIHRoZSBtaW51cyBzaWduIGAtYC4KCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGFycmFuZ2UoLVJlbGF0aXZlX1BlcmNlbnQpICU+JQogIGdsaW1wc2UoKQpgYGAKCk9LLCBzbyBpdCBsb29rcyBsaWtlIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMgYXJlIHJlYWxseSBvdmVyLWNvbnN1bWVkIGluIHNvbWUgcGFydHMgb2YgdGhlIHdvcmxkIQoKUmVjYWxsIGZyb20gdGhlIHN1cHBsZW1lbnRhcnkgdGFibGUgZnJvbSB0aGUgYXJ0aWNsZSB0aGF0IG92ZXItY29uc3VtcHRpb24gb2Ygc3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyBpcyBhc3NvY2lhdGVkIHdpdGggYm90aCBEaWFiZXRlcyBtZWxsaXR1cyB0eXBlIDIgYW5kIElzY2hlbWljIGhlYXJ0IGRpc2Vhc2UuIFRoaXMgW2FydGljbGVdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzUxMzMwODQvKXt0YXJnZXQ9Il9ibGFuayJ9IGRpc2N1c3NlcyBzb21lIG9mIHRoZSBjb250cm92ZXJzeSBvdmVyIHRoZSBwb3RlbnRpYWwgaGVhbHRoIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBoaWdoIGNvbnN1bXB0aW9uIG9mIHN1Z2FyLgoKSXQgc3RpbGwgbG9va3MgcXVpdGUgYmFkIGlmIHdlIGxvb2sgYXQgdGhlIG90aGVyIGNhbGN1bGF0ZWQgcGVyY2VudGFnZSB2YWx1ZXMuIApgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICAgc2VsZWN0KGNvbnRhaW5zKCJwZXJjZW50IikpICU+JQogICBzdW1tYXJ5KCkKYGBgClNvIHNvbWUgcGxhY2VzIGFyZSBzdGlsbCBjb25zdW1pbmcgNCwwMDAgcGVyY2VudCBtb3JlIHRoYW4gdGhlIHVwcGVyIHJhbmdlIG9mIHRoZSBzdWdnZXN0ZWQgb3B0aW1hbCBpbnRha2UuCgpMZXQncyB0YWtlIGEgbG9vayBhdCBnbG9iYWwgbGV2ZWxzOgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICAgICAgIGZpbHRlcihmb29kID09ICJzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2VzIiAmIAogICAgIGxvY2F0aW9uX25hbWUgPT0gIkdsb2JhbCIpCmBgYAoKRm9yIHRob3NlIHdobyBhcmUgbGVzcyBmYW1pbGlhciB3aXRoIHRoZSBtZXRyaWMgc3lzdGVtIHdoZXJlIGdyYW1zIGFyZSBlcXVpdmFsZW50IHRvIG1pbGxpbGl0ZXJzLCBpdCBtYXkgYmUgdXNlZnVsIHRvIHJlYWxpemUgaG93IG1hbnkgZmx1aWQgb3VuY2VzIHRoZSBtYXggYW1vdW50IG9mIGNvbnN1bXB0aW9uIHBlciBkYXkgKH4yNDhnIGZvciB0aGUgYHVwcGVyYCB2YWx1ZSBmb3IgQ29zdGEgUmljYSkgYWN0dWFsbHkgaXMuIAoKVGhlcmUgYXJlIDAuMzUyNDcgb3VuY2VzIGluIG9uZSBncmFtLgoKYGBge3J9CiN0b3AgYW1vdW50IGluIG91bmNlcwowLjM1MjQ3KjI0Ny45MzQyIApgYGAKCk9LLCBzbyB0aGUgdG9wIGNvbnN1bWVycyBhcmUgZHJpbmtpbmcgYWJvdXQgODcgZmx1aWQgb3VuY2VzIHBlciBkYXkuIFNpbmNlIHRoZXJlIGFyZSAxMiBvdW5jZXMgaW4gYSBzaW5nbGUgY2FuIG9mIHNvZGEsIHRoaXMgaXMgYWJvdXQgYHIgODcvMTJgIHNvZGFzIHBlciBkYXkuIEdsb2JhbGx5IG9uIGF2ZXJhZ2UsIG1hbGVzIGFyZSBkcmlua2luZyBhcm91bmQgYHIgcm91bmQoKDY1LjUqMC4zNTI0NykvMTIsIDMpYCBzb2RhcyB3b3J0aCBvZiBzd2VldGVuZWQgYmV2ZXJhZ2VzLCB3aGlsZSBmZW1hbGVzIGFyZSBkcmlua2luZyBhYm91dCBgciByb3VuZCgoNDcuNyowLjM1MjQ3KS8xMiwgMylgLgoKCkxldCdzIHRha2UgYSBsb29rIGF0IHdoYXQgaXMgdW5kZXItY29uc3VtZWQ6CgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBhcnJhbmdlKFJlbGF0aXZlX1BlcmNlbnQpICU+JQogIGdsaW1wc2UoKQpgYGAKCk9uIHRoZSBvdGhlciBoYW5kLCBpdCBsb29rcyBsaWtlIHNvbWUgcGxhY2VzIGFyZSBjb25zdW1pbmcgYWxtb3N0IG5vIHBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcy4gVGhlc2UgYXJlIGZhdHMgdGhhdCBmb3VuZCBpbiBwbGFudC1iYXNlZCBzb3VyY2VzIGxpa2Ugc2VlZHMgYW5kIG51dHMuIEFjY29yZGluZyB0byBhbiBbYXJ0aWNsZV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNDg1OTQwMS8pe3RhcmdldD0iX2JsYW5rIn0gYWJvdXQgcG9seXVuc2F0dXJhdGVkIGZhdHR5IGFjaWRzIGFuZCBpdHMgaW5mbHVlbmNlIG9uIGhlYWx0aDoKCj4gQ29yb25hcnkgaGVhcnQgZGlzZWFzZSAoQ0hEKSBpcyB0aGUgbGVhZGluZyBjYXVzZSBvZiBkZWF0aCB3b3JsZHdpZGUgLi4uIFRoZSB0eXBlcyBvZiBkaWV0YXJ5IGZhdHMgY29uc3VtZWQgcGxheSBhbiBpbXBvcnRhbnQgcm9sZSBpbiBDSEQgcmlzaywgcmVwcmVzZW50aW5nIGtleSBtb2RpZmlhYmxlIHJpc2sgZmFjdG9ycy4uLkluIHBhcnRpY3VsYXIsIGhpZ2hlciBpbnRha2VzIG9mIHRyYW5zIGZhdCAoVEZBKSBhbmQgb2Ygc2F0dXJhdGVkIGZhdCAoU0ZBKSByZXBsYWNpbmcgz4nigJA2IChu4oCQNikgcG9seXVuc2F0dXJhdGVkIGZhdCAoUFVGQSkgYXJlIGFzc29jaWF0ZWQgd2l0aCBpbmNyZWFzZWQgQ0hELi4uIHdoZXJlYXMgaGlnaGVyIGludGFrZSBvZiBQVUZBIHJlcGxhY2luZyBlaXRoZXIgU0ZBIG9yIGNhcmJvaHlkcmF0ZSBpcyBhc3NvY2lhdGVkIHdpdGggbG93ZXIgcmlzay4KCgpMZXQncyBnZXQgYW4gaWRlYSBhYm91dCBob3cgY291bnRyaWVzIGNvbXBhcmUgaW4gdGVybXMgb2YgaG93IG1hbnkgb2YgdGhlIGRpZXRhcnkgZmFjdG9ycyBhcmUgY29uc3VtZWQgYXQgdGhlIG9wdGltYWwgbGV2ZWwgKHRoZSBgb3B0X2FjaGlldmVkYCB2YXJpYWJsZSkuCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBjb3VudChvcHRfYWNoaWV2ZWQpCmBgYAoKTG9va3MgbGlrZSBvdmVyYWxsLCBvbmx5IGByIHJvdW5kKDE1MjAvNDM2MCoxMDAsIDIpYCUgIG9mIGRpZXRhcnkgZmFjdG9ycyBmb3IgYWxsIHRlc3RlZCBwb3B1bGF0aW9ucyB3ZXJlIGF0IG9wdGltYWwgbGV2ZWxzLgoKTGV0J3MgZ2V0IGFuIGlkZWEgYWJvdXQgaG93IGNvdW50cmllcyBjb21wYXJlIG9uIHRoaXMgbWV0cmljLgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KCmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgY291bnQob3B0X2FjaGlldmVkLCBsb2NhdGlvbl9uYW1lKSAlPiUKICBmaWx0ZXIob3B0X2FjaGlldmVkID09ICJZZXMiKSAlPiUKICBhcnJhbmdlKC1uKSAlPiUKICAjIHRoaXMgYWxsb3dzIHVzIHRvIHNob3cgdGhlIGZ1bGwgb3V0cHV0CiAgcHJpbnQobiA9IDFlMykKCmBgYAojIyMjCgpJdCBsb29rcyBhcyB0aG91Z2ggb24gYXZlcmFnZSB0aGUgcG9wdWxhdGlvbnMgKGJvdGggbWFsZSBhbmQgZmVtYWxlIHNlcGFyYXRlbHkpIGluIFFhdGFyLCBSd2FuZGEsIGFuZCBUdXJrZXkgY29uc3VtZWQgdGhlIG9wdGltYWwgbGV2ZWwgb2YgaW50YWtlIGZvciB0aGUgbGFyZ2VzdCBudW1iZXIgb2YgZGlldGFyeSBmYWN0b3JzICgxMyBvdXQgb2YgMzAgKGZvciB0aGUgMTUgZGlldGFyeSBmYWN0b3JzIGZvciBtYWxlcyBhbmQgZmVtYWxlcykpLgoKSW4gY29udHJhc3QsIHRoZSBDemVjaCBSZXB1YmxpYywgR3JlZW5sYW5kLCBIdW5nYXJ5LCBTbG92YWtpYSwgU2xvdmVuaWEsIGFuZCB0aGUgVW5pdGVkIFN0YXRlcyBoYWQgdGhlIHBvb3Jlc3QgY29uc3VtcHRpb24gcmF0ZXMgKDI3IG91dCBvZiAzMCB3ZXJlIG5vdCBhdCBvcHRpbWFsIGxldmVscykuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBjb3VudChvcHRfYWNoaWV2ZWQsIGxvY2F0aW9uX25hbWUpICU+JQogIGZpbHRlcihvcHRfYWNoaWV2ZWQgPT0gIk5vIikgJT4lCiAgYXJyYW5nZSgtbikgJT4lCiAgI3RvIHNob3cgZnVsbCBvdXRwdXQKICBwcmludChuID0gMWUzKQoKYGBgCiMjIyMKCkxldCdzIGxvb2sgYXQgdGhlIHJhdyBVUyBkYXRhOgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIobG9jYXRpb25fbmFtZSA9PSAiVW5pdGVkIFN0YXRlcyIpICU+JQogIGdsaW1wc2UoKQoKYGBgCgpMZXQncyBzZWUgaG93IG1hbGVzIGFuZCBmZW1hbGVzIGNvbXBhcmUgZm9yIGFjaGlldmluZyB0aGUgb3B0aW1hbCBpbnRha2UsIGFjcm9zcyBhbGwgY291bnRyaWVzOgoKYGBge3J9CmNvdW50KGRpZXRfYW5kX2d1aWRlbGluZXMsIHNleCwgb3B0X2FjaGlldmVkKQpgYGAKTG9va3MgcHJldHR5IHNpbWlsYXIsIGJ1dCBpdCBtYXkgYmUgYSBiaXQgYmV0dGVyIGZvciBmZW1hbGVzLiBXZSB3aWxsIGV2YWx1YXRlIHRoaXMgZnVydGhlciBiZWxvdy4KCkluIG9yZGVyIHRvIGFzc2VzcyB3aGF0IHdlIGhhdmUgb2JzZXJ2ZWQgc28gZmFyIGluIGEgZ3JhcGhpY2FsIHdheSwgd2Ugd2lsbCBtYWtlIHNvbWUgZGF0YSB2aXN1YWxpemF0aW9ucy4gT25lIHdheSB3ZSBjYW4gZG8gdGhpcyBpcyB3aXRoIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4KVGhlIFtnZ3Bsb3QyXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gcGFja2FnZSBjcmVhdGVzIHBsb3RzIGJ5IGJ1aWxkaW5nIHRoZSBwbG90IGNvbXBvbmVudHMgcGllY2UgYnkgcGllY2UsIHVzaW5nIGAibGF5ZXJzImAuCgpXaXRoIGBnZ3Bsb3QyYCB3ZSBzZWxlY3Qgd2hhdCBkYXRhIHdlIHdvdWxkIGxpa2UgdG8gcGxvdCB1c2luZyB0aGUgZmlyc3QgZnVuY3Rpb24gKGBnZ3Bsb3QoKWApIGFuZCB0aGVuIHdlIGFkZCBvbiBhZGRpdGlvbmFsIGxheWVycyBvZiBjb21wbGV4aXR5ICh0aGVzZSBsYXllcnMgY2FuIGV2ZW4gaW52b2x2ZSBkaWZmZXJlbnQgZGF0YSkuIFRoZSBgYWVzKClgIGFyZ3VtZW50IHNwZWNpZmllcyB3aGF0IGFzcGVjdHMgb2YgdGhlIGRhdGEgd2lsbCBiZSBwbG90dGVkIHdoZXJlLiBUaGUgYGdlb21fKmAgZnVuY3Rpb24gc3BlY2lmaWVzIHdoYXQgdHlwZSBvZiBwbG90IHRvIGNyZWF0ZSAoZS5nLiBgZ2VvbV9oaXN0b2dyYW0oKWAgY3JlYXRlcyBhIGhpc3RvZ3JhbSkuIE5vdGljZSBpbiB0aGUgZm9sbG93aW5nIGNvZGUgaG93IHRoZXJlIGlzIGEgcGx1cyBzaWduIGJldHdlZW4gdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24gYW5kIHRoZSBgZ2VvbV9iYXIoKWAgZnVuY3Rpb247IHRoaXMgaXMgaG93IHdlIGNvbWJpbmUgZGlmZmVyZW50IHBsb3QgbGF5ZXJzLiAKCldlIHdpbGwgc2VlIGxhdGVyIGhvdyB3ZSBjYW4gYWRkIG1hbnkgbGF5ZXJzIHRvIHBsb3RzIHdpdGggYGdncGxvdDJgLiBGb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB1c2luZyBgZ2dwbG90MmAsIHNlZSB0aGlzIFtjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWhlYWx0aGV4cGVuZGl0dXJlL29jcy1oZWFsdGhleHBlbmRpdHVyZS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZ2dwbG90KGFlcyhvcHRfYWNoaWV2ZWQsIGZpbGwgPSBzZXgpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKCkNvbnRpbnVpbmcgd2l0aCBgZ2dwbG90MmAgd2Ugd2lsbCBub3cgY3JlYXRlIGEgZGlmZmVyZW50IHR5cGUgb2YgcGxvdC4gVGhpcyB0aW1lIHdlIHdpbGwgY3JlYXRlIGEgc2VyaWVzIG9mIGJveCBwbG90cy4gV2Ugd2lsbCB1c2UgdGhlIGBmYWNldF93cmFwKClgIGZ1bmN0aW9uIG9mIGdncGxvdDIgdG8gYWxsb3cgdXMgdG8gY3JlYXRlIG1hbnkgZGlmZmVyZW50IHBsb3RzIHNpbXVsdGFuZW91c2x5LiBJbiB0aGlzIGNhc2Ugd2UgY2FuIGxvb2sgYXQgYm94IHBsb3RzIGZvciB0aGUgZGlmZmVyZW50IGRpZXRhcnkgZmFjdG9ycyBjb2xvcmVkIGJ5IHNleC4gVGhlIGBzY2FsZXNgIGFyZ3VtZW50IHdoZW4gc2V0IHRvIGAiZnJlZSJgIG1lYW5zIHRoYXQgZWFjaCBvZiB0aGUgc2VxdWVudGlhbCBwbG90IGNyZWF0ZWQgYnkgdGhlIGZhY2V0IGNhbiBoYXZlIGEgZGlmZmVyZW50IHNjYWxlIGZvciB0aGUgeSBheGlzLCBvdGhlcndpc2UsIGJ5IGRlZmF1bHQgdGhleSBhcmUgY29uc3RyYWluZWQgdG8gdGhlIHNhbWUgc2NhbGUuIFNpbmNlIG91ciBkaWV0YXJ5IGZhY3RvcnMgYXJlIG1lYXN1cmVkIG9uIHZlcnkgZGlmZmVyZW50IHNjYWxlcywgd2UgZG8gbm90IHdhbnQgdGhpcyBjb25zdHJhaW50IGhlcmUuCgoKYGBge3J9CiMgd2Ugd2lsbCBjcmVhdGUgYSBuZXcgdmFyaWFibGUgd2l0aCBmb29kIG5hbWVzIHdpdGggbmV3IGxpbmVzCmRpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZShmb29kX3RvX3Bsb3QgPQogIHN0cl9yZXBsYWNlKCAKICBzdHJpbmcgPSBwdWxsKGRpZXRfYW5kX2d1aWRlbGluZXMsZm9vZCksIAogIHBhdHRlcm4gPSAiICIsIAogIHJlcGxhY2VtZW50ID0gIlxuIikpCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGdncGxvdChhZXMoeSA9IFJlbGF0aXZlX1BlcmNlbnQgLAogICAgICAgICAgICAgeCA9IHNleCwgCiAgICAgICAgIGNvbG9yID0gc2V4KSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH4gZm9vZF90b19wbG90LCAKICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlIiwKICAjc3BlY2lmaWVzIHRoZSBudW1iZXIgb2Ygcm93cyBvZiBzdWJwbG90cwogICAgICAgICAgICAgbnJvdyA9IDMsIAogICNtb3ZlcyB0aGUgZm9vZCBsYWJlbCB0byB0aGUgcmlnaHQKICAgICAgICAgICAgIHN0cmlwLnBvc2l0aW9uID0gInJpZ2h0IikgKwogICN0aGlzIGNoYW5nZXMgdGhlIHNpemUgb2YgdGhlIGZvbnQgZm9yIHRoZSBsYWJlbHMKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDcwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQpgYGAKCgpJZiB3ZSBqdXN0IGxvb2sgYXQgZGlmZmVyZW5jZXMgYnkgc2V4IGZvciB0aGUgc3BlY2lmaWMgZGlldGFyeSBmYWN0b3JzLCAgbWFsZXMgYXBwZWFyIHRvIHBvdGVudGlhbGx5IGNvbnN1bWUgbW9yZSBvZiBtYW55IG9mIHRoZSBmYWN0b3JzLCBpbmNsdWRpbmcgcG9zc2libHkgbW9yZSBzb2RpdW0sIGZpYmVyLCBjYWxjaXVtLCByZWQgbWVhdCwgYW5kIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMgdGhhbiBmZW1hbGVzLiBGZW1hbGVzIG1heSBjb25zdW1lIG1vcmUgZnJ1aXQuCgojIyMgIEV4cGxvcmluZyB0aGUgZGF0YSBzZXBhcmF0ZWQgYnkgYWdlCgpOb3cgd2Ugd2lsbCB0YWtlIGEgbG9vayBhdCB0aGUgZGF0YSB0aGF0IGlzIHNlcGFyYXRlZCBieSBhZ2UgZ3JvdXBzLgoKRmlyc3QsIHJlY2FsbCB0aGF0IHdlIGhhdmUgMTUgZGlmZmVyZW50IGFnZSBncm91cHMgc3RhcnRpbmcgZnJvbSBhZ2UgMjUgdG8gOTUgcGx1cy4KYGBge3J9CmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKIGNvdW50KGFnZV9ncm91cF9uYW1lKQpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9MTV9CnNlcF9hZ2VfZGlldF9kYXRhICU+JQogIGdncGxvdChhZXMoeSA9IG1lYW4gLCB4PSBhZ2VfZ3JvdXBfbmFtZSwgY29sID0gc2V4KSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH5mb29kLCBzY2FsZXMgPSAiZnJlZSIsIG5yb3cgPSA2KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA3MCwgaGp1c3QgPSAxKSkKYGBgCgpXZSBjYW4gc2VlIGZyb20gdGhlc2UgcGxvdHMgdGhhdCB0aGVyZSBhcHBlYXIgdG8gYmUgYWdlIGRpZmZlcmVuY2VzIGFuZCBnZW5kZXIgZGlmZmVyZW5jZXMgZm9yIHNvbWUgb2YgdGhlIGRpZmZlcmVudCBkaWV0YXJ5IGZhY3RvcnMuIFdlIHdpbGwgd29yayB0byBjcmVhdGUgY2xlYXJlciBmaWd1cmVzIGxhdGVyIG9uLiBIb3dldmVyIHRoZXNlIGluaXRpYWwgZmlndXJlcyBoYXZlIGdpdmVuIHVzIGEgYmV0dGVyIHNlbnNlIG9mIHRoZSBkYXRhIHRoYXQgd2UgYXJlIHdvcmtpbmcgd2l0aC4KCgojIyAqKkRhdGEgQW5hbHlzaXMqKgoqKioKCmBgYHtyLCBlY2hvID0gRkFMU0V9CiMgRm9yIGluc3RydWN0b3JzIHdobyB3aXNoIHRvIHN0YXJ0IGF0IHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBsb2FkIHRoZSBkYXRhCmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZF9kYXRhLnJkYSIpKQpgYGAKClJlY2FsbCB3aGF0IG91ciBtYWluIHF1ZXN0aW9ucyB3ZXJlOgoKIyMjIyB7Lm1haW5fcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBPdXIgbWFpbiBxdWVzdGlvbnMgYXJlOiA8L3U+PC9iPgoKMSkgV2hhdCBhcmUgdGhlIGdsb2JhbCB0cmVuZHMgZm9yIHBvdGVudGlhbGx5IGhhcm1mdWwgZGlldHM/CjIpIEhvdyBkbyBtYWxlcyBhbmQgZmVtYWxlcyBjb21wYXJlPwozKSBIb3cgZG8gZGlmZmVyZW50IGFnZSBncm91cHMgY29tcGFyZSBmb3IgdGhlc2UgZGlldGFyeSBmYWN0b3JzPwo0KSBIb3cgZG8gZGlmZmVyZW50IGNvdW50cmllcyBjb21wYXJlPyBJbiBwYXJ0aWN1bGFyLCBob3cgZG9lcyB0aGUgVVMgY29tcGFyZSB0byBvdGhlciBjb3VudHJpZXMgaW4gdGVybXMgb2YgZGlldCB0cmVuZHM/CgojIyMjCgpXZSBoYXZlIHNvbWUgZ2VuZXJhbCBzZW5zZSBhYm91dCBnbG9iYWwgdHJlbmRzIGZvciB0aGUgcmlzay1hc3NvY2lhdGVkIGRpZXRhcnkgZmFjdG9ycywgaG93ZXZlciB3ZSB3YW50IHRvIGtub3cgbW9yZS4KCldlIGFyZSBpbnRlcmVzdGVkIGluIGhvdyBtdWNoIHRoZSBnZW5kZXJzIGRpZmZlciwgaG93IG11Y2ggdGhlIDE1IGRpZmZlcmVudCBhZ2UgZ3JvdXBzIGRpZmZlciwgYW5kIGhvdyB0aGUgMTk1IGNvdW50cmllcyBjb21wYXJlLiAKCkluIG9yZGVyIHRvIG1ha2UgW2luZmVyZW5jZXNdKGh0dHBzOi8vd3d3LmJyaXRhbm5pY2EuY29tL3NjaWVuY2UvaW5mZXJlbmNlLXN0YXRpc3RpY3MpIGFib3V0IHRoZXNlIGNvbXBhcmlzb25zLCBpdCBpcyBoZWxwZnVsIHRvIHBlcmZvcm0gc3RhdGlzdGljYWwgdGVzdHMuIFRoZXNlIHRlc3RzIGNhbiBoZWxwIHVzIHRvIGRldGVybWluZSB0aGUgc3RyZW5ndGggb2YgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIGNvbnN1bXB0aW9uIG9mIHRoZSBkaWV0YXJ5IGZhY3RvcnMgKG91ciBvdXRjb21lIHZhcmlhYmxlKSBhbmQgc2V4LCBhZ2UgZ3JvdXAsIGFuZCBjb3VudHJ5IGlkZW50aXR5IChvdXIgcHJlZGljdG9yIHZhcmlhYmxlcykuIE9uZSB3YXkgdG8gbG9vayBhdCB0aGUgc3RyZW5ndGggb2YgYXNzb2NpYXRpb24gYmV0d2VlbiB2YXJpYWJsZXMgaXMgdG8gdXNlIGEgc3RhdGlzdGljYWwgbWV0aG9kIGNhbGxlZCAqKnJlZ3Jlc3Npb24qKi4KCklmIHdlIG1lYXN1cmUgY29uc3VtcHRpb24gdXNpbmcgZWl0aGVyIHJhdyBjb25zdW1wdGlvbiBvciB0aGUgcGVyY2VudCBvZiBvcHRpbWFsIGNvbnN1bXB0aW9uLCB0aGVuIG91ciBvdXRjb21lIHZhcmlhYmxlIGlzIHdoYXQgd2UgY2FsbCAqKmNvbnRpbnVvdXMqKiwgYmVjYXVzZSBvdXIgdmFsdWVzIGNhbiB0YWtlIG9uIGFueSBudW1lcmljIHZhbHVlIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgcG9zc2libGUgdmFsdWVzLiAgVG8gbG9vayBhdCB0aGUgc3RyZW5ndGggb2YgYXNzb2NpYXRpb24gd2l0aCBhIGNvbnRpbnVvdXMgb3V0Y29tZSwgd2UgY2FuIHVzZSAqKmxpbmVhciByZWdyZXNzaW9uKiouCgpJZiwgaW5zdGVhZCwgd2UgbWVhc3VyZSBjb25zdW1wdGlvbiBieSB3aGV0aGVyIG9yIG5vdCB0aGUgb3B0aW1hbCBsZXZlbCBvZiBjb25zdW1wdGlvbiB3YXMgYWNoaWV2ZWQgKCJ5ZXMiIG9yICJubyIpLCB0aGVuIG91ciBvdXRjb21lIHdvdWxkIGJlIGNvbnNpZGVyZWQgKipiaW5hcnkqKiwgbWVhbmluZyBpdCBjYW4gdGFrZSBvbmx5IHR3byBwb3NzaWJsZSB2YWx1ZXMuICBUbyBsb29rIGF0IHRoZSBzdHJlbmd0aCBvZiBhc3NvY2lhdGlvbiB3aXRoIGEgYmluYXJ5IG91dGNvbWUsIHdlIGNhbiB1c2UgKipsb2dpc3RpYyByZWdyZXNzaW9uLioqICBUaGVyZSBhcmUgb3RoZXIgcmVncmVzc2lvbiBtZXRob2QgZm9yIGRpZmZlcmVudCB0eXBlcyBvZiBvdXRjb21lcyBhcyB3ZWxsOyBzZWUgW2hlcmVdKGh0dHBzOi8vd3d3LmFuYWx5dGljc3ZpZGh5YS5jb20vYmxvZy8yMDE1LzA4L2NvbXByZWhlbnNpdmUtZ3VpZGUtcmVncmVzc2lvbi8pe3RhcmdldD0iX2JsYW5rIn0gZm9yIGEgZ3VpZGUgb24gZGlmZmVyZW50IHR5cGVzIG9mIHJlZ3Jlc3Npb24gbWV0aG9kcy4KCkluIHRoaXMgY2FzZSBzdHVkeSwgd2Ugd2lsbCBmb2N1cyBvbiB0aGUgb3V0Y29tZSBvZiB0aGUgcGVyY2VudCBvZiBvcHRpbWFsIGNvbnN1bXB0aW9uIChgUmVsYXRpdmVfUGVyY2VudGApLCBzbyB3ZSB3aWxsIGZvY3VzIG91ciBhbmFseXNpcyBvbiBsaW5lYXIgcmVncmVzc2lvbi4gIAoKWW91IG1heSBoYXZlIGFscmVhZHkgbGVhcm5lZCB0aGF0IG9uZSBjYW4gY29tcGFyZSBhIGNvbnRpbnVvdXMgb3V0Y29tZSBiZXR3ZWVuIHR3byBncm91cHMgdXNpbmcgYSAkdCQtdGVzdC4gRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhlICR0JC10ZXN0IHNlZSB0aGlzIFtjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWJwLXJ1cmFsLWFuZC11cmJhbi1vYmVzaXR5Lyl7dGFyZ2V0PSJfYmxhbmsifS4gIEFuZCBwZXJoYXBzIHlvdSBoYXZlIGhlYXJkIGFib3V0IEFOT1ZBIChBTmFseXNpcyBPZiBWQXJpYW5jZSkgZm9yIGNvbXBhcmluZyBhIGNvbnRpbnVvdXMgb3V0Y29tZSBhY3Jvc3MgbW9yZSB0aGFuIHR3byBncm91cHMuICBJdCB0dXJucyBvdXQgdGhhdCBib3RoIHRoZSAkdCQtdGVzdCBhbmQgQU5PVkEgYXJlIHNwZWNpYWxpemVkIHR5cGVzIG9mIFtsaW5lYXIgcmVncmVzc2lvbl0oaHR0cHM6Ly9saW5kZWxvZXYuZ2l0aHViLmlvL3Rlc3RzLWFzLWxpbmVhci8pe3RhcmdldD0iX2JsYW5rIn0uIFdlIHdpbGwgdXNlIGVhY2ggb2YgdGhlc2UgdGVzdHMgdG8gaW52ZXN0aWdhdGUgcGF0dGVybnMgb2YgY29uc3VtcHRpb24gZm9yIGRpZXRhcnkgZmFjdG9ycyB0aGF0IGNvbnRyaWJ1dGUgdG8gaGVhbHRoIHJpc2sgYW5kIHdlIHdpbGwgbG9vayBhdCBob3cgd2UgY2FuIG9idGFpbiBlcXVpdmFsZW50IHJlc3VsdHMgd2l0aCByZWdyZXNzaW9uLgoKIyMjIExpbmVhciBSZWdyZXNzaW9uCgpTbyB3aGF0IGlzIGxpbmVhciByZWdyZXNzaW9uPyBIb3cgY2FuIHdlIHVzZSByZWdyZXNzaW9uIHRvIGNvbXBhcmUgb3VyIGdyb3VwcyBvZiBpbnRlcmVzdCBhbmQgbG9vayBhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZ3JvdXAgaWRlbnRpdHkgYW5kIGNvbnN1bXB0aW9uIG9mIGRpZXRhcnkgZmFjdG9ycyBhc3NvY2lhdGVkIHdpdGggaGVhbHRoIHJpc2s/CgpUaGUgc3RhdGlzdGljYWwgdmVyc2lvbiBvZiB0aGUgdGVybSByZWdyZXNzaW9uIHdhcyBjb2luZWQgaW4gMTg3NyBpbiB0aGlzIFthcnRpY2xlXShodHRwOi8vZ2FsdG9uLm9yZy9lc3NheXMvMTg3MC0xODc5L2dhbHRvbi0xODc3LXR5cGljYWwtbGF3cy1oZXJlZGl0eS5wZGYgKXt0YXJnZXQ9Il9ibGFuayJ9IGFib3V0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBoZXJlZGl0YXJ5IHRyYWl0cyBhbmQgcG9wdWxhdGlvbiBhdmVyYWdlcy4gVGhlIGF1dGhvciBwYXJ0aWN1bGFybHkgZm9jdXNlZCBvbiBbaGVpZ2h0XShodHRwczovL3plbm9kby5vcmcvcmVjb3JkLzE0NDk1NDgjLlhsZl85aE5LaWhjKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBraW5zaGlwIG9yIHJlbGF0ZWRuZXNzLiBUaGUgd29yZCBpdHNlbGYgbWVhbnMgYCJ0byBnbyBiYWNrIHRvIGEgc2ltcGxlciBzdGF0ZSJgLiBJdCB3YXMgbm90aWNlZCB0aGF0IGluZGl2aWR1YWxzIHdpdGggcGFyZW50cyB3aG8gaGFkIGFuIGV4dHJlbWUgdHJhaXQsIHN1Y2ggYXMgZXhjZXB0aW9uYWwgaGVpZ2h0LCB0ZW5kZWQgdG8gaGF2ZSBhIGhlaWdodCBtb3JlIHNpbWlsYXIgdG8gdGhlIGF2ZXJhZ2Ugb2YgdGhlIHBvcHVsYXRpb24gdGhhbiB0aGUgZXh0cmVtZSBoZWlnaHQgb2YgdGhlaXIgcGFyZW50cy4gRm9yIGV4YW1wbGUgaWYgcGFyZW50cyB3ZXJlIHZlcnkgdGFsbCwgdGhlaXIgY2hpbGRyZW4gd2VyZSBsaWtlbHkgdG8gYmUgYSBiaXQgc2hvcnRlciB0aGFuIHRoZWlyIHBhcmVudHMgYW5kIHRoZXJlZm9yZSBjbG9zZXIgdG8gdGhlIHBvcHVsYXRpb24gYXZlcmFnZS4gVGh1cyB0aGUgY2hpbGRyZW4gcmVncmVzc2VkIHRvd2FyZHMgdGhlIG1lYW4gb3IgaW4gdGhlIGF1dGhvcidzIHdvcmRzIHRoZSBvZmZzcHJpbmcgc2hvd2VkOgoKPiAiYSAqcmVncmVzc2lvbiogdG93YXJkcyBtZWRpb2NyaXR5IgoKU2VlIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SZWdyZXNzaW9uX3Rvd2FyZF90aGVfbWVhbil7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGlzIGhpc3RvcnkuCgpXaGVuIHdlIHRoaW5rIGFib3V0IHRoaXMgZnJvbSBhIHN0YXRpc3RpY2FsIHN0YW5kcG9pbnQsIHJlZ3Jlc3Npb24gYWxsb3dzIHVzIHRvIGVzdGltYXRlIG9yICoqcmVncmVzcyoqIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMgd2l0aCBhICJzaW1wbGUiIG1vZGVsLiBXZSBkbyB0aGlzIGJ5ICoqZXN0aW1hdGluZyB0aGUgbWVhbioqIG9mIGFuIG91dGNvbWUsIGdpdmVuIGEgdmFsdWUgb2YgYW4gaW5wdXQgb3IgcHJlZGljdG9yIHZhcmlhYmxlLiBUaGlzIGNhbiBiZSB1c2VmdWwgZm9yICoqcHJlZGljdGluZyBmdXR1cmUgdmFsdWVzKiogb2YgdGhlIG91dGNvbWUgYmFzZWQgb24gdGhlIGFwcHJveGltYXRpb24gb2YgdGhlIHJlYWwgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhYmxlcyB3aXRoaW4gdGhlIG1vZGVsLCBvciBqdXN0IGZvciB1bmRlcnN0YW5kaW5nIGhvdyBkaWZmZXJlbnQgdmFyaWFibGVzIGFyZSByZWxhdGVkIHRvIG9uZSBhbm90aGVyLgoKV2Ugd2lsbCBzdGFydCBieSBjb25zaWRlcmluZyAqKnNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbioqLCB3aGVyZSB3ZSBoYXZlIG9uZSBjb250aW51b3VzIHByZWRpY3RvciB2YXJpYWJsZSBhbmQgb25lIGNvbnRpbnVvdXMgb3V0Y29tZSB2YXJpYWJsZSwgYXMgc2hvd24gYmVsb3c6CmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI0MDBwdHgifQpzZXQuc2VlZCgxNSkKZGF0YV94IDwtIHNhbXBsZSgxOjEwLCAxMCwgcmVwbGFjZSA9IFRSVUUpCmRhdGFfeSA8LSBkYXRhX3ggKyBybm9ybSgxMCwgMCwgMTApCnRoZWRhdGEgPC0gYmluZF9jb2xzKHggPSBkYXRhX3gsIHkgPSBkYXRhX3kpCgpnZ3Bsb3QoZGF0YSA9IHRoZWRhdGEsIGFlcyh4ID0geCwgeSA9IHkpKSArCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKV2Ugd2FudCB0byBpZGVudGlmeSBhICJiZXN0IGZpdCIgbGluZSB0aGF0IHN1bW1hcml6ZXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZXNlIHR3byB2YXJpYWJsZXMuICBXZSBjYW4gc28gdGhpcyB1c2luZyB0aGUgb3JkaW5hcnkgbGVhc3Qgc3F1YXJlcyBtZXRob2QsIHdoaWNoIGNob29zZXMgdGhlIGxpbmUgdGhhdCBiZXN0IGZpdHMgdGhlIGRhdGEgYnkgbWluaW1pemluZyB0aGUgc3VtIG9mIHRoZSBzcXVhcmVkIHZlcnRpY2FsIGRpc3RhbmNlcyBiZXR3ZWVuIGVhY2ggcG9pbnQgYW5kIHRoZSBsaW5lLiBJbiB0aGUgYWJvdmUgZXhhbXBsZSwgdGhpcyBsaW5lIHR1cm5zIG91dCB0byBiZToKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjQwMHB0eCJ9CnNldC5zZWVkKDE1KQpkYXRhX3ggPC0gc2FtcGxlKDE6MTAsIDEwLCByZXBsYWNlID0gVFJVRSkKZGF0YV95IDwtIGRhdGFfeCArIHJub3JtKDEwLCAwLCAxMCkKdGhlZGF0YSA8LSBiaW5kX2NvbHMoeCA9IGRhdGFfeCwgeSA9IGRhdGFfeSkKCmdncGxvdChkYXRhID0gdGhlZGF0YSwgYWVzKHggPSB4LCB5ID0geSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIAogICAgICAgICAgICAgICAgICBzZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCAKICAgICAgICAgICAgIGZvcm11bGEgPSB5IH4geCkgKyAKICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24oc2l6ZSA9IDYpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKRml0dGluZyBhIGxpbmUgdG8gdGhlIGRhdGEgbGlrZSB0aGlzIGFsbG93cyB1cyB0byBjcmVhdGUgYSBmb3JtdWxhIGZvciB0aGUgbGluZSB1c2luZyBhbiAqKmludGVyY2VwdCoqIGFuZCBhICoqc2xvcGUqKiwgc28gdGhhdCB3ZSBjYW4gdGhlbiBlc3RpbWF0ZSAqKm1lYW4qKiB2YWx1ZXMgb2YgJFkkIChkZXBlbmRlbnQvb3V0Y29tZSB2YXJpYWJsZSkgZ2l2ZW4ga25vd24gdmFsdWVzIG9mICRYJCAoaW5kZXBlbmRlbnQvcHJlZGljdG9yL2NvdmFyaWF0ZS9leHBsYW5hdG9yeSB2YXJpYWJsZShzKSkuIFBlb3BsZSB3aWxsIGFsc28gc2F5IHRoYXQgd2UgYXJlICJyZWdyZXNzaW5nICRZJCBvbiAkWCQiLgogCllvdSBtYXkgaGF2ZSBzZWVuIHRoZSBmb3JtdWxhIGZvciBhIGxpbmUgd3JpdHRlbiBsaWtlIHRoaXM6CgokJFkgPSBtWCArIGIkJCAKCjxjZW50ZXI+IG9yIDwvY2VudGVyPgokJFkgPSBhWCArIGIkJAoKSW4gdGhpcyBjYXNlICRtJCBvciAkYSQgaXMgdGhlIHNsb3BlIG9mIHRoZSBsaW5lIGFuZCAkYiQgaXMgYSBjb25zdGFudCBhbmQgcmVwcmVzZW50cyB0aGUgeS1pbnRlcmNlcHQgb3IgdGhlIHBvaW50IHdoZXJlIHRoZSB5IGF4aXMgaXMgY3Jvc3NlZCBieSB0aGUgbGluZSwgd2hlbiAkeCA9IDAkLgoKSW4gcmVncmVzc2lvbiwgd2UgdXN1YWxseSB3cml0ZSB0aGlzIG1vZGVsIGxpa2UgdGhpczoKCiQkWSA9IFxiZXRhX3sxfVggK1xiZXRhX3swfSQkCgpOb3cgJFxiZXRhX3sxfSQsIGNhbGxlZCAiYmV0YSBvbmUiIiwgaXMgb3VyIHNsb3BlIGFuZCAkXGJldGFfezB9JCwgY2FsbGVkICJiZXRhIHplcm8iIChvciAiYmV0YSBuYXVnaHQiKSwgaXMgb3VyIGludGVyY2VwdC4gIEluIG91ciBleGFtcGxlIGFib3ZlLCB0aGUgc2xvcGUgb2YgdGhlIHJlZ3Jlc3Npb24gbGluZSBpcyAkXGJldGFfezF9ID0gMi4zJCBhbmQgdGhlIGludGVyY2VwdCBpcyAkXGJldGFfezB9ID0gLTYuNiQuCgpJbXBvcnRhbnRseSB0aGUgc2xvcGUgKCRcYmV0YV97MX0kKSBnaXZlcyB1cyBhIHF1YW50aXRhdGl2ZSBtZWFzdXJlIG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgKCRYJCkgb24gdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAoJFkkKS4gIEluIHBhcnRpY3VsYXIsICRcYmV0YV97MX0kIHRlbGxzIGhvdyB0aGUgZXhwZWN0ZWQgZGlmZmVyZW5jZSBpbiB0aGUgJFkkIHZhbHVlIGZvciBhIGRpZmZlcmVuY2Ugb2YgMSB1bml0IGluIHRoZSAkWCQgdmFsdWUuCgpJdCdzIHBvc3NpYmxlIHRoYXQgdGhlIHJlZ3Jlc3Npb24gbGluZSB3aWxsIHBlcmZlY3RseSBmaXQgdGhlIGRhdGEsIGFuZCBhbGwgcG9pbnRzIHdpbGwgbGllIG9uIHRoZSBsaW5lIHdpdGggbm8gZGlzdGFuY2UgdG8gdGhlIGxpbmU6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiNDAwcHR4In0KCmRhdGFfeCA8LSBzYW1wbGUoMToxMDAsIDIwLCByZXBsYWNlID0gVFJVRSkKZGF0YV95IDwtIGRhdGFfeCArIDEwCnRoZWRhdGEgPC0gYmluZF9jb2xzKHggPSBkYXRhX3gsIHkgPSBkYXRhX3kpCgpnZ3Bsb3QoZGF0YSA9IHRoZWRhdGEsIGFlcyh4ID0geCwgeSA9IHkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCAKICAgICAgICAgICAgICAgICAgc2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgCiAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHgpICsgCiAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKHNpemUgPSA2KSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKQpgYGAKCkluIHRoaXMgY2FzZSwgdGhlIHNsb3BlIG9yICRcYmV0YV97MX0kIGlzIDEgYW5kIHRoZSBpbnRlcmNlcHQgJFxiZXRhX3swfSQgaXMgMTAgYW5kIGV2ZXJ5IG9ic2VydmVkIGRhdGEgcG9pbnQgbGllcyBleGFjdGx5IG9uIHRoZSBsaW5lLCBlLmcuLCB3ZSBjYW4gc2VlIHRoYXQgd2hlbiAkWCQgaXMgNTAsICRZJCBpcyBleGFjdGx5IDYwLiBUaGlzIGlzIHZlcnkgdW51c3VhbCBpbiBzdGF0aXN0aWNhbCBhbmFseXNpcyBob3dldmVyLCBhcyBvZnRlbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdmFyaWFibGVzIGlzIG1vcmUgY29tcGxpY2F0ZWQgYW5kIHRoZXJlIGlzIG1vcmUgbm9pc2UgaW4gb3VyIGRhdGEuIEluIHRoZXNlIG90aGVyIGNhc2VzIHRoZXJlIHdpbGwgYmUgZ3JlYXRlciBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgbGluZSBhbmQgdGhlIHBvaW50cy4gCgpMaWtlIHRoaXMgcmVncmVzc2lvbjoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI0MDBwdHgifQpzZXQuc2VlZCgxMykKdGhlZGF0YSAlPD4lIG11dGF0ZSh5MiA9IHJub3JtKDIwLCBzZCA9IDQwKSkKCmdncGxvdChkYXRhID0gdGhlZGF0YSwgYWVzKHggPSB4LCB5ID0geTIpKSArCiAgICAgICAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIAogICAgICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSB5IH4geCkgKwogICAgICAgICAgICBnZW9tX3BvaW50KCkgKwpzdGF0X3JlZ2xpbmVfZXF1YXRpb24oc2l6ZSA9IDYpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCgpgYGAKCkluIHRoaXMgY2FzZSwgYmVjYXVzZSB0aGVyZSBpcyBzb21lIHZlcnRpY2FsIGRpc3RhbmNlIGJldHdlZW4gdGhlIGxpbmUgYW5kIHRoZSBkYXRhIHBvaW50cywgdGhlcmUgaXMgYSBiaXQgb2Ygd2hhdCBpcyBjYWxsZWQgImVycm9yIiBpbiB0aGUgbW9kZWwuIFRoZSBmb3JtdWxhIGZvciB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gJFgkIGFuZCAkWSQgZG9lcyBub3QgcGVyZmVjdGx5IGRlc2NyaWJlIHRoZSBkYXRhLiBUaGUgdmVydGljYWwgZGlzdGFuY2UgYmV0d2VlbiB0aGUgbGluZSBhbmQgZWFjaCBkYXRhIHBvaW50IGlzIHdoYXQgd2UgY2FsbCBhIFtyZXNpZHVhbF0oaHR0cHM6Ly93d3cuc3RhdGlzdGljc2hvd3RvLmRhdGFzY2llbmNlY2VudHJhbC5jb20vcmVzaWR1YWwvKXt0YXJnZXQ9Il9ibGFuayJ9LiBPdXIgbGVhc3Qgc3F1YXJlcyBtZXRob2QgZmluZHMgdGhlIGxpbmUgd2l0aCB0aGUgbWluaW1pemVkIHZhbHVlIG9mIHRoZSBzdW0gb2YgdGhlIHNxdWFyZWQgcmVzaWR1YWwgdmFsdWVzLgoKQ2hlY2sgb3V0IHRoaXMgW2ludGVyYWN0aXZlIGV4cGxhbmF0aW9uXShodHRwOi8vc2V0b3NhLmlvL2V2L29yZGluYXJ5LWxlYXN0LXNxdWFyZXMtcmVncmVzc2lvbi8pe3RhcmdldD0iX2JsYW5rIn0gb2YgaG93IHRoZSBvcmRpbmFyeSBsZWFzdCBzcXVhcmVzIG1ldGhvZCB3b3Jrcy4KCkhlcmUgaXMgYW4gaW1hZ2Ugb2Ygd2hhdCB3ZSBhcmUgc2F5aW5nIGFib3V0IHRoZSBvcmRpbmFyeSBsZWFzdCBzcXVhcmVzIHJlZ3Jlc3Npb24gdG8gZml0IGEgbGluZSB0byBkYXRhOgo8Y2VudGVyPiFbXShodHRwczovL3FwaC5mcy5xdW9yYWNkbi5uZXQvbWFpbi1xaW1nLTNiMGQ3NjU1YWM3NmVkZjEyNDFmOTcwMTVlZTc1NWI0KTwvY2VudGVyPgoKIyMjIyMjIFtbc291cmNlXShodHRwczovL3FwaC5mcy5xdW9yYWNkbi5uZXQvbWFpbi1xaW1nLTNiMGQ3NjU1YWM3NmVkZjEyNDFmOTcwMTVlZTc1NWI0KV0KClRoaXMgYmFzaWMgY29uY2VwdCBvZiBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gYW4gYmUgZXh0ZW5kZWQgdG8gYWxsb3cgZm9yIG1vcmUgdGhhbiBvbmUgY292YXJpYXRlICh0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzLCBvciB4J3MpOyB0aGlzIGlzIGNhbGxlZCAqKm11bHRpdmFyaWFibGUqKiBsaW5lYXIgcmVncmVzc2lvbi4gICBXaXRoIG1vcmUgdGhhbiBvbmUgaW5kZXBlbmRlbnQgdmFyaWFibGUsIHdlIGNhbid0IHZpc3VhbGl6ZSB0aGVzZSByZWxhdGlvbnNoaXBzIGVhc2lseSB3aXRoIGEgbGluZSBvbiBhIHR3by1kaW1lbnNpb25hbCBwYWdlLCBidXQgdGhlIG1hdGhlbWF0aWNhbCBjb25jZXB0IHJlbWFpbnMgaW4gc29tZSBzZW5zZSB0aGUgc2FtZS4KClIgaGFzIGl0J3Mgb3duIHdheSBvZiByZXByZXNlbnRpbmcgdGhlIHJlZ3Jlc3Npb24gZXF1YXRpb24gaW4gY29kZS4gRm9yIGEgZ3VpZGUgb24gaG93IHRvIHBlcmZvcm0gcmVncmVzc2lvbnMgaW4gUiBzZWUgW2hlcmVdKGh0dHA6Ly93d3cubW9udGVmaW9yZS51bGcuYWMuYmUvfmt2YW5zdGVlbi9HQklPMDAwOS0xL2FjMjAwOTIwMTAvQ2xhc3M4L1VzaW5nJTIwUiUyMGZvciUyMGxpbmVhciUyMHJlZ3Jlc3Npb24ucGRmKXt0YXJnZXQ9Il9ibGFuayJ9LgoKSW4gUiB3ZSBpbmRpY2F0ZSBhIGxpbmVhciBtb2RlbCBsaWtlIHRoaXM6CmBgYHtyLCBldmFsID0gRkFMU0V9CnkgfiB4CmBgYApIZXJlIG91ciByZXNwb25zZS9vdXRjb21lIHZhcmlhYmxlIGlzIG9uIHRoZSBsZWZ0IG9mIHRoZSBgfmAgd2hpbGUgb3VyIGNvdmFyaWF0ZXMvZXhwbGFuYXRvcnkgdmFyaWFibGVzIGFyZSBvbiB0aGUgcmlnaHQgb2YgdGhlIGB+YC4KCgpCZWZvcmUgd2UgZ2V0IHN0YXJ0ZWQsIGxldCdzIHJlbW92ZSB0aGUgZ2xvYmFsIHZhbHVlcyBmcm9tIG91ciBkYXRhIGFuZCBzZXQgdGhlbSBhc2lkZSwgYXMgdGhpcyBpcyByZWFsbHkgYSBjb21wb3NpdGUgb2YgYWxsIHRoZSBjb3VudHJ5IHZhbHVlcy4KCmBgYHtyfQpnbG9iYWwgPC0gZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUgCiAgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIkdsb2JhbCIpCmRpZXRfYW5kX2d1aWRlbGluZXMgJTw+JSAKICBmaWx0ZXIobG9jYXRpb25fbmFtZSAhPSAiR2xvYmFsIikKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUgCiAgZmlsdGVyKGxvY2F0aW9uX25hbWUgIT0gIkdsb2JhbCIpCmBgYAoKIyMjICR0JC10ZXN0IGFuZCBsaW5lYXIgcmVncmVzc2lvbgoKU2luY2Ugd2Ugd2lsbCBiZSBjb3ZlcmluZyBhIGxvdCBvZiBkaWZmZXJlbnQgc3RhdGlzdGljYWwgY29uY2VwdHMgaGVyZSwgd2Ugd2lsbCB3YW50IHRvIGZvY3VzIGFyZSBhbmFseXNpcyBvbiBhIHNpbmdsZSBkaWV0YXJ5IGZhY3Rvci4gTGV0J3MgY2hvb3NlIG9uZSBvZiB0aGUgZGlldGFyeSBmYWN0b3JzIHRoYXQgYXBwZWFyZWQgdG8gcG90ZW50aWFsbHkgaGF2ZSBhIGRpZmZlcmVuY2UgYmV0d2VlbiBnZW5kZXJzIGJhc2VkIG9uIG91ciBmaWd1cmUgaW4gb3VyIGV4cGxvcmF0b3J5IGFuYWx5c2lzLgoKPiAiSWYgd2UganVzdCBsb29rIGF0IGRpZmZlcmVuY2VzIGJ5IHNleCBmb3IgdGhlIHNwZWNpZmljIGRpZXRhcnkgZmFjdG9ycywgIG1hbGVzIGFwcGVhciB0byBwb3RlbnRpYWxseSBjb25zdW1lIG1vcmUgb2YgbWFueSBvZiB0aGUgZmFjdG9ycywgaW5jbHVkaW5nIHBvc3NpYmx5IG1vcmUgc29kaXVtLCBmaWJlciwgY2FsY2l1bSwgcmVkIG1lYXQsIGFuZCBzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2VzIHRoYW4gZmVtYWxlcy4gRmVtYWxlcyBtYXkgY29uc3VtZSBtb3JlIGZydWl0LiIKCkxldCdzIHRha2UgYSBsb29rIGF0IHJlZCBtZWF0LgoKV2UgY2FuIGNvbXBhcmUgdGhlIHJlbGF0aXZlIHBlcmNlbnQgb2YgcmVkIG1lYXQgY29uc3VtcHRpb24gb2YgbWFsZXMgYW5kIGZlbWFsZXMgYXJvdW5kIHRoZSB3b3JsZCB1c2luZyB0aGUgd2VsbCBrbm93biAkdCQtdGVzdCB1c2luZyB0aGUgYHQudGVzdCgpYCBmdW5jdGlvbiBhbmQgYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB1c2luZyB0aGUgYGxtKClgIGZ1bmN0aW9uIChib3RoIGFyZSBpbmNsdWRlZCBpbiBgc3RhdHNgIHBhY2thZ2UgdGhhdCBpcyBpbnN0YWxsZWQgd2l0aCBSIGJ5IGRlZmF1bHQpIGFuZCB3ZSB3aWxsIGdldCB0aGUgKipzYW1lIHJlc3VsdHMqKi4gU2VlIFtoZXJlXShodHRwczovL3NjaWVudGlmaWNhbGx5c291bmQub3JnLzIwMTcvMDYvMDgvJHQkLXRlc3QtYXMtbGluZWFyLW1vZGVscy1yLyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgYWRkaXRpb25hbCBleHBsYW5hdGlvbiBhYm91dCB3aHkgdGhhdCBpcyB0aGUgY2FzZS4gW0hlcmVdKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9ldmVyeXRoaW5nLWlzLWp1c3QtYS1yZWdyZXNzaW9uLTVhM2JmMjJjNDU5Yyl7dGFyZ2V0PSJfYmxhbmsifSBhbmQgW2hlcmVdKGh0dHBzOi8vbGluZGVsb2V2LmdpdGh1Yi5pby90ZXN0cy1hcy1saW5lYXIvKXt0YXJnZXQ9Il9ibGFuayJ9IGFyZSBhbHNvIGdyZWF0IHNvdXJjZXMgYWJvdXQgaG93IG1hbnkgY29tbW9ubHkga25vd24gc3RhdGlzdGljYWwgdGVzdHMgYXJlIHNwZWNpYWxpemVkIGZvcm1zIG9mIHJlZ3Jlc3Npb24uCgpCZWZvcmUgd2UgZ2V0IHN0YXJ0ZWQsIGxldCdzIHRoaW5rIGFib3V0IHRoZSBhc3N1bXB0aW9ucyBvZiBib3RoIGFuIGluZGVwZW5kZW50IHNhbXBsZXMgJHQkLXRlc3QgYW5kIGxpbmVhciByZWdyZXNzaW9uLgoKCiMjIyMgSW5kZXBlbmRlbnQgc2FtcGxlcyAkdCQtdGVzdCBhc3N1bXB0aW9uczoKCjEpIE5vcm1hbGl0eSBvZiB0aGUgb3V0Y29tZSBpbiBlYWNoIGdyb3VwICh0aGlzIGlzIG5vdCBhcyBtdWNoIG9mIGFuIGlzc3VlIGlmIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGlzIHJlbGF0aXZlbHkgbGFyZ2UsIGkuZS4sIHRvdGFsIG4gPiAzMCAtIHdoaWNoIGlzIGluZGVlZCB0aGUgY2FzZSBmb3IgdXMhKQoyKSBFcXVhbCB2YXJpYW5jZSBiZXR3ZWVuIHRoZSB0d28gZ3JvdXBzCjMpIEluZGVwZW5kZW50IG9ic2VydmF0aW9ucwoKIyMjIyBMaW5lYXIgcmVncmVzc2lvbiBhc3N1bXB0aW9uczoKCjEpICoqTCoqIChsaW5lYXIpIC0gVGhlcmUgaXMgYSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIG91dGNvbWUgdmFyaWFibGUgYW5kIGVhY2ggY292YXJpYXRlLgoKMikgKipJKiogKGluZGVwZW5kZW50KSAtIFRoZSBvdXRjb21lIGZvciBpbmRpdmlkdWFsIG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQgZnJvbSBvbmUgYW5vdGhlciwgZ2l2ZW4gdGhlIGNvdmFyaWF0ZXMgaW4gdGhlIG1vZGVsLgoKMykgKipOKiogKG5vcm1hbCkgLSBUaGUgcmVzaWR1YWxzIChlcnJvcnMpIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZC4gTm90ZSB0aGF0IHRoZSB2YXJpYWJsZXMgdGhlbXNlbHZlcyBkbyBub3QgbmVlZCB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZC4KCjQpICoqRSoqIChlcXVhbCB2YXJpYW5jZXMpIC0gVGhlIHZhcmlhbmNlIG9mIHRoZSByZXNpZHVhbHMgaXMgY29uc3RhbnQgYWNyb3NzIGNvdmFyaWF0ZSBncm91cHMuICBUaGlzIGlzIGNhbGxlZCBbaG9tb3NjZWRhc3RpY2l0eV0oaHR0cHM6Ly93d3cuc3RhdGlzdGljc3NvbHV0aW9ucy5jb20vaG9tb3NjZWRhc3RpY2l0eS8pe3RhcmdldD0iX2JsYW5rIn0uIEluIG90aGVyIHdvcmRzIHRoZSByZXNpZHVhbHMgYXJlIG9mIHNpbWlsYXIgc2l6ZSBhbG9uZyB0aGUgcmVncmVzc2lvbiBsaW5lLgoKSXQncyBhbHNvIGltcG9ydGFudCB0aGF0IGlmIHRoZXJlIGFyZSBtdWx0aXBsZSBwcmVkaWN0b3IgdmFyaWFibGVzLCB0aGF0IHRoZXNlIGFyZSBub3QgdG9vIGhpZ2hseSBjb3JyZWxhdGVkLgoKU2VlIFtoZXJlXShodHRwczovL3d3dy5qbXAuY29tL2VuX3VzL3N0YXRpc3RpY3Mta25vd2xlZGdlLXBvcnRhbC93aGF0LWlzLXJlZ3Jlc3Npb24vc2ltcGxlLWxpbmVhci1yZWdyZXNzaW9uLWFzc3VtcHRpb25zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gZm9yIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGFzc3VtcHRpb25zIG9mIGxpbmVhciByZWdyZXNzaW9ucy4KCk5vdGljZSB0aGF0IG1hbnkgb2YgdGhlIGFzc3VtcHRpb25zIGJldHdlZW4gJHQkLXRlc3RzIGFuZCBsaW5lYXIgcmVncmVzc2lvbiBhcmUgc2ltaWxhciAtLSBlYWNoIGhhcyBhbiBhc3N1bXB0aW9uIG9mIG5vcm1hbGl0eSwgZXF1YWwgdmFyaWFuY2UsIGFuZCBpbmRlcGVuZGVuY2UhCgojIyMjIEFzc2Vzc2luZyBub3JtYWxpdHkKCkZpcnN0IHdlIHdpbGwgZXhwbG9yZSB0aGUgc2hhcGUgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGVzZSByZWxhdGl2ZSBwZXJjZW50IG9mIHJlZCBtZWF0IGNvbnN1bXB0aW9uLiAgV2UgY2FuIGRvIHRoaXMgYnkgbG9va2luZyBhdCBhIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gb2YgdGhlIGBSZWxhdGl2ZV9QZXJjZW50YCB2YXJpYWJsZSBmb3IgcmVkIG1lYXQgY29uc3VtcHRpb24uICBXZSB3aWxsIHVzZSB0aGUgYGdlb21faGlzdG9ncmFtKClgIG9mIHRoZSBgZ2dwbG90MmBwYWNrYWdlIHRvIGNyZWF0ZSBhIGhpc3RvZ3JhbSB0byBldmFsdWF0ZSB0aGUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbnMgb2Ygb3VyIGRhdGEuIFRoZSBgZmFjZXRfd3JhcCgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UgYWxsb3dzIHVzIHRvIGxvb2sgYXQgZGlmZmVyZW50IHBhcnRzIG9mIG91ciBkYXRhIGluIHNlcGFyYXRlIHBsb3RzLiAgSGVyZSB3ZSBjYW4gY29tcGFyZSB0aGUgZGlzdHJpYnV0aW9uIGZvciBtYWxlcyBhbmQgZmVtYWxlcy4KCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGdncGxvdChhZXMoeCA9IFJlbGF0aXZlX1BlcmNlbnQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZmFjZXRfd3JhcCh+IHNleCkgCmBgYAoKVGhpcyBgUmVsYXRpdmVfUGVyY2VudGAgdmFyaWFibGUgYXBwZWFycyB0byBoYXZlIGEgcmlnaHQgc2tldyBmb3IgYm90aCBtYWxlIGFuZCBmZW1hbGUgaW5kaXZpZHVhbHMuICBXZSBjYW4gYWxzbyBzZWUgdGhpcyBieSBsb29raW5nIGF0IG5vcm1hbCBRdWFudGlsZS1RdWFudGlsZSAoUS1RKSBwbG90cyBvZiB0aGlzIHZhcmlhYmxlLiAgUmVtZW1iZXIgdGhhdCBpbiBhIFEtUSBwbG90LCBwb2ludHMgYXdheSBmcm9tIHRoZSBsaW5lIGluZGljYXRlIG9uZSBvZiB0aGUgZGlzdHJpYnV0aW9ucyBpcyBtb3JlIHNrZXdlZCB0aGFuIHRoZSBvdGhlci4gIEluIHRoaXMgY2FzZSwgd2Ugc2VlIHRoYXQgdGhlIHZhbHVlcyBpbiBhcmUgc2FtcGxlIGFyZSBza2V3ZWQgcmVsYXRpdmUgdG8gdGhlIHRoZW9yZXRpY2FsIG5vcm1hbCBkaXN0cmlidXRpb24uIFtIZXJlXShodHRwOi8vd3d3LnVjZC5pZS9lY29tb2RlbC9SZXNvdXJjZXMvUVFwbG90c19XZWJWZXJzaW9uLmh0bWwpIGlzIGEgZ3JlYXQgcmVmZXJlbmNlIGZvciBpbnRlcnByZXRpbmcgUS1RIHBsb3RzLgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBSZWxhdGl2ZV9QZXJjZW50KSkgKwogIGZhY2V0X3dyYXAofiBzZXgpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpCmBgYAoKV2UgY2FuIGNvbnNpZGVyIHRyYW5zZm9ybWluZyBvdXIgZGF0YSB0byBtYWtlIGl0IG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIFdoZW4gZGF0YSBpcyBoaWdobHkgcmlnaHQgc2tld2VkLCBhIGxvZyB0cmFuc2Zvcm1hdGlvbiBpcyBvZnRlbiBoZWxwZnVsLgoKTGV0J3MgdGFrZSBhIGxvb2sgYSB0aGUgbG9nICh3aXRoIGJhc2UgMTApIG9mIG91ciBgUmVsYXRpdmVfUGVyY2VudGAgdmFyaWFibGU6CgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gc2V4KSAKCmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSkpICsKICBmYWNldF93cmFwKH4gc2V4KSArCiAgZ2VvbV9xcSgpICsKICBnZW9tX3FxX2xpbmUoKQpgYGAKCk9LLCBzbyBub3cgb3VyIGhpc3RvZ3JhbXMgbG9vayBmYWlybHkgbm9ybWFsLiBJdCBpc24ndCBwZXJmZWN0LCBidXQgd2UgaGF2ZSBhIGxhcmdlIG51bWJlciBvZiBzYW1wbGVzLCBzbyB0aGlzIGlzIGdvb2QgZm9yIG91ciAkdCQtdGVzdCBhc3N1bXB0aW9ucy4gCgojIyMjIEFzc2Vzc2luZyBlcXVhbCB2YXJpYW5jZXMKClRoZSBuZXh0IHRoaW5nIHdlIG5lZWQgdG8gY2hlY2sgaXMgaWYgdGhlIHZhcmlhbmNlIGluIHJlZCBtZWF0IGNvbnN1bXB0aW9uIGlzIHNpbWlsYXIgYmV0d2VlbiB0aGUgdHdvIGdlbmRlciBncm91cHMuIFdlIGNhbiB1c2UgdGhlIGB2YXIudGVzdCgpYCAgb2YgdGhlIGBzdGF0c2AgcGFja2FnZSB1c2luZyB0aGUgbG9nLW5vcm1hbGl6ZWQgZGF0YSwgYXMgdGhpcyBkYXRhIGlzIGZhaXJseSBub3JtYWxseSBkaXN0cmlidXRlZC4KCkJlY2F1c2Ugd2UgYXJlIHBpcGluZyBpbiBvdXIgZGF0YSB0byB0aGlzIHRlc3QgZnVuY3Rpb24sIHdlIG5lZWQgdG8gaW5kaWNhdGUgdGhhdCB0aGlzIGlzIHRoZSBkYXRhIHdlIGludGVuZCB0byB1c2UgYnkgdXNpbmcgYC5gIGZvciB0aGUgYGRhdGFgIGFyZ3VtZW50LiAgVGhpcyBpcyBhIGhhbmR5IHRpcCB3aGVuIHBpcGluZyBpbnRvIGEgZnVuY3Rpb24gb3V0c2lkZSBvZiB0aGUgYHRpZHl2ZXJzZWAgd2hlcmUgdGhlIGZpcnN0IGFyZ3VtZW50IGlzbid0IGEgZGF0YSBzZXQuCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICB2YXIudGVzdChsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSB+IHNleCwgZGF0YSA9IC4pCmBgYAoKVGhlIHAgdmFsdWUgPiAuMDUgZm9yIHRoaXMgdGVzdCwgdGh1cyB3ZSBjYW4gY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBub3QgZW5vdWdoIGV2aWRlbmNlIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlcmUgaXMgbm8gZGlmZmVyZW5jZSBpbiB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRpc3RyaWJ1dGlvbnMsIHNvIHdlIGNvbmNsdWRlIHRoYXQgdmFyaWFuY2UgaXMgcm91Z2hseSBlcXVhbC4KCiMjIyMgQ29tcGFyaW5nIGEgJHQkLXRlc3QgdG8gbGluZWFyIHJlZ3Jlc3Npb24KCk5vdyBsZXQncyBjb21wYXJlIHRoZSBjb25zdW1wdGlvbiBvZiByZWQgbWVhdCBhY3Jvc3MgZ2VuZGVycyB1c2luZyBib3RoIGEgJHQkLXRlc3QgYW5kIGEgbGluZWFyIHJlZ3Jlc3Npb24uIEZpcnN0IG91ciBpbmRlcGVuZGVudCBzYW1wbGVzICR0JC10ZXN0OgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICB0LnRlc3QobG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBzZXgsIGRhdGEgPSAuLCB2YXIuZXF1YWwgPSBUUlVFKQpgYGAKCk5vdGljZSBoZXJlIHRoYXQgc2FtcGxlIG1lYW5zIGZvciB0aGUgdHdvIGdyb3VwcyBhcmUgMS44MCBhbmQgMS45OCBmb3IgbWFsZXMgYW5kIGZlbWFsZXMsIHJlc3BlY3RpdmVseS4gIFNvIHRoYXQgbWVhbnMgdGhlIGRpZmZlcmVuY2UgaW4gc2FtcGxlIG1lYW5zIGlzIDEuODAgLSAxLjk4ID0gLTAuMTguICBXZSBhbHNvIHNlZSBhIHRlc3Qgc3RhdGlzdGljIG9mICR0JCA9IC01LjMyIGFuZCBhIHZlcnkgc21hbGwgJHAkLXZhbHVlLiAgCgpMZXQncyBleGFtaW5lIHRoZSBzYW1lIHJlbGF0aW9uc2hpcCB1c2luZyBsaW5lYXIgcmVncmVzc2lvbjoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG0obG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBzZXgsIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKYGBgCgpMb29rIGF0IHRoZSByZXN1bHRzIGZvciB0aGUgc2xvcGUgb2YgdGhlIHJlZ3Jlc3Npb24gbGluZSwgaW5kaWNhdGVkIGJ5IHRoZSBgc2V4TWFsZWAgcm93IGluIHRoZSBvdXRwdXQgYWJvdmUuICBOb3RpY2UgaG93IHRoZSAkdCQtdmFsdWUgYW5kIHRoZSAkcCQtdmFsdWUgbWF0Y2ggb3VyICR0JC10ZXN0ISAgKFdlbGwsIHRoZSBzaWducyBhcmUgc3dpdGNoZWQgaW4gZWFjaCBjYXNlIC0tIHRoZSAkdCQgdmFsdWUgaXMgbmVnYXRpdmUgaW4gdGhlIGB0LnRlc3QoKWAgb3V0cHV0IGJlY2F1c2UgdGhlIG1hbGUgZ3JvdXAgaXMgYmVpbmcgdXNlZCBhcyByZWZlcmVuY2UgZ3JvdXAsIHdoaWxlIHRoZSBmZW1hbGUgZ3JvdXAgaXMgYmVpbmcgdXNlZCBhcyB0aGUgcmVmZXJlbmNlIGdyb3VwIGluIGBsbSgpYCkuIFdlIGNhbiBmaXggdGhpcyB1c2luZyB0aGUgYGZjdF9pbm9yZGVyKClgIGZ1bmN0aW9uIG9mIHRoZSBgZm9yY2F0c2AgcGFja2FnZSB3aGljaCBpcyBhbGwgYWJvdXQgZmFjdG9ycy4gVGhpcyBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gb3JkZXIgdGhlIGZhY3RvciBieSB3aGF0IGFwcGVhcnMgZmlyc3QuIEluIHRoaXMgY2FzZSAibWFsZSIgYXBwZWFycyBmaXJzdCwgc28gbm93IG91ciBvdXRwdXQgd2lsbCBtYXRjaCB0aGF0IG9mIHRoZSBgbG0oKWAgZnVuY3Rpb24uCgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZV9hdCh2YXJzKHNleCksIGZhY3RvcikKCmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG0obG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBzZXgsIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKCmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgbXV0YXRlX2F0KHZhcnMoc2V4KSwgZm9yY2F0czo6ZmN0X2lub3JkZXIpICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIHQudGVzdChsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSB+IHNleCwgZGF0YSA9IC4sIAogICAgICAgICB2YXIuZXF1YWwgPSBUUlVFKQoKYGBgCgpOb3cgdGhleSBtYXRjaC4gTm90aWNlIHRoYXQgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbHNvIG1hdGNoLCBib3RoIHJlc3VsdHMgc2hvdyAzODggZGVncmVlcyBvZiBmcmVlZG9tLiBXZSBhcmUgZXN0aW1hdGluZyB0d28gcGFyYW1ldGVycyBmb3IgdGhlIGxpbmVhciBtb2RlbCB0aGUgdHdvICRcYmV0YSQgY29lZmZpY2llbnRzLCAodGhlIHNsb3BlIGFuZCBpbnRlcmNlcHQpLCBhbmQgZm9yIHRoZSAkdCQtdGVzdCB3ZSBhcmUgZXN0aW1hdGluZyB0aGUgbWVhbnMgb2YgdHdvIGdyb3VwcyAobWFsZXMgYW5kIGZlbWFsZXMpLiBPdmVyYWxsIHdlIGhhdmUgdHdvIHNhbXBsZXMgKG1hbGUgYW5kIGZlbWFsZSkgZm9yIGVhY2ggb2YgdGhlIDE5NSBjb3VudHJpZXMuIAoKVGh1cywgdGhlIG92ZXJhbGwgc2FtcGxlIG51bWJlciBpczogICRuID0gMTk1KjIgPSAzOTAkCgokJGRmID0gbiAtICMgcGFyYW1ldGVycyBlc3RpbWF0aW5nJCQgClRodXMgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBjYW4gYmUgY2FsY3VsYXRlZCBhczogICRkZiA9IDM5MCAtMiA9IDM4OCQKCkxldCdzIGxvb2sgbW9yZSBjbG9zZWx5IGF0IHRoZSBsaW5lYXIgcmVncmVzc2lvbiBvdXRwdXQgZnJvbSBgbG0oKWAuICBPdXIgZXN0aW1hdGVkIGludGVyY2VwdCAoJFxiZXRhX3swfSQpIGlzIDEuODAsIHdoaWNoIGNhbiBiZSBpbnRlcnByZXRlZCBhcyB0aGUgbWVhbiB2YWx1ZSB3aGVuIHNleCBpcyBub3QgbWFsZSAoc28gaW4gdGhpcyBjYXNlIHdoZW4gc2V4IGlzIGZlbWFsZSkuICBUaGlzIG1hdGNoZXMgdGhlIHNhbXBsZSBtZWFuIG9mIHRoZSBmZW1hbGUgZ3JvdXAgaW4gdGhlIGB0LnRlc3QoKWAgb3V0cHV0LiAKCk91ciBlc3RpbWF0ZWQgc2xvcGUgKCRcYmV0YV97MX0kKSBpcyAwLjE4LCB3aGljaCBjYW4gYmUgaW50ZXJwcmV0ZWQgYXMgdGhlIHNsb3BlIG9mIHRoZSByZWdyZXNzaW9uIGxpbmUgb3IgKip0aGUgbWVhbiBjaGFuZ2UgaW4gJFkkIGFzc29jaWF0ZWQgd2l0aCBvbmUtdW5pdCBpbmNyZWFzZSBpbiAkWCQqKi4gIFNpbmNlIG91ciAkWCQgdmFyaWFibGUgaXMgc2V4LCBhIG9uZS11bml0IGNoYW5nZSBtZWFucyBtb3ZpbmcgZnJvbSBvbmUgZ3JvdXAgdG8gYW5vdGhlci4gIFNvIHdlIGNhbiB0aGluayBvZiB0aGUgc2xvcGUgYXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbWVhbnMgb2YgdGhlIHR3byBncm91cHMsIG1hbGUgKCRYJD0xKSBtaW51cyBmZW1hbGUgKCRYJCA9IDApLiAgSWYgd2UgY2FsY3VsYXRlIHRoaXMgZGlmZmVyZW5jZSBpbiBtZWFucyBhcyBjYWxjdWxhdGVkIGluIHRoZSBgdC50ZXN0KClgIG91dHB1dCwgd2UgZ2V0IHRoZSB2YWx1ZSBvZiAkXGJldGFfezF9JCAodGhlIHNsb3BlIG9yIHRoZSBgc2V4TWFsZSBlc3RpbWF0ZWApIG9mIHRoZSBgbG0oKWAgb3V0cHV0IQoKTWVhbiBvZiBtYWxlcyAtIE1lYW4gb2YgZmVtYWxlcwokMS45ODMyNTkgLSAxLjc5ODg3MiA9MC4xODQzODckCgpDb29sISAgRm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIG91dHB1dCBvZiBgbG0oKWAgc2VlIFtoZXJlXShodHRwczovL2ZlbGlwZXJlZ28uZ2l0aHViLmlvL2Jsb2cvMjAxNS8xMC8yMy9JbnRlcnByZXRpbmctTW9kZWwtT3V0cHV0LUluLVIpe3RhcmdldD0iX2JsYW5rIn0uCgpBZnRlciBmaXR0aW5nIG91ciBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCwgd2UgY2FuIHVzZSB0aGUgYmFzZSBgcGxvdCgpYCBmdW5jdGlvbiB0byBnZXQgaW5mb3JtYXRpb24gYWJvdXQgb3VyIHRoZSBtb2RlbCByZXNpZHVhbHMgdG8gaGVscCB1cyBhc3Nlc3Mgd2hldGhlciBhbnkgb2YgdGhlIGFzc3VtcHRpb25zIG9mIGxpbmVhciByZWdyZXNzaW9uIGFyZSB2aW9sYXRlZC4gSGVyZSB3ZSBjaG9vc2UgdG8gdmlldyB0aGUgZmlyc3QgdGhyZWUgb2YgdGhlc2UgcGxvdHMgd2l0aCBgd2hpY2ggPSAxOjNgLgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG0obG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBzZXgsIGRhdGEgPSAuKSAlPiUKICBwbG90KHdoaWNoID0gMTozKQpgYGAKClRoZSBzZWNvbmQgcGxvdCBzaG93cyB1cyB0aGF0IG91ciByZXNpZHVhbHMgYXJlIHNsaWdodGx5IG5lZ2F0aXZlbHkgKG9yIGxlZnQpIHNrZXdlZC4gIFdlIGNhbiBzZWUgYWxzbyBzZWUgdGhlIHNwcmVhZCBvZiB0aGUgcmVzaWR1YWxzIGlzIHNpbWlsYXIgYmV0d2VlbiBtYWxlcyBhbmQgZmVtYWxlcywgYXMgdGhlIGZpcnN0IGFuZCB0aGlyZCBwbG90IHNob3cgc2ltaWxhciBzcHJlYWRzIG9mIHZhbHVlcyBpbiB0aGUgdHdvIGxpbmVzLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIGFzc3VtcHRpb24gb2YgaG9tb3NjZWRhc3RpY2l0eSBpcyBtZXQuICBIZXJlIGlzIHdoYXQgdGhlc2UgcGxvdHMgd291bGQgbG9vayBsaWtlIGlmIHRoZSB2YXJpYW5jZSB3ZXJlIG5vdCB0aGUgc2FtZSBiZXR3ZWVuIHRoZSBncm91cHM6CgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBtdXRhdGUoZXhhbXBsZV9wZXJjID0gY2FzZV93aGVuKAojIHRoaXMgd2lsbCBhcnRpZmljYWxseSBtYWtlIG91ciBmZW1hbGUgZGF0YSBoYXZlIGRpZmZlcmVudCAKIyAgdmFyYWluY2UgZnJvbSB0aGUgbWFsZSBkYXRhCiAgICBzZXggPT0gIkZlbWFsZSIgfiAgbG9nKFJlbGF0aXZlX1BlcmNlbnQpLAogICAgc2V4ID09ICJNYWxlIiB+IFJlbGF0aXZlX1BlcmNlbnQpKSAlPiUKICAgIGxtKGxvZzEwKGV4YW1wbGVfcGVyYykgfiBzZXgsIGRhdGEgPSAuKSAlPiUKICBwbG90KHdoaWNoID0gMTozKQoKYGBgCgpJbiB0aGlzIGNhc2UgdGhlIHNwcmVhZCBvZiB0aGUgcG9pbnRzIGlzIGNsZWFybHkgbGVzcyBmb3Igb25lIGdyb3VwIGNvbXBhcmVkIHRvIHRoZSBvdGhlci4gIElmIHdlIHNhdyBwbG90cyBsaWtlIHRoZXNlLCB3ZSB3b3VsZCBiZSBjb25jZXJuZWQgdGhlIGFzc3VtcHRpb24gb2YgaG9tb3NjZWRhc3RpY2l0eSB3YXMgdmlvbGF0ZWQuCgojIyMjIEFzc2Vzc2luZyBpbmRlcGVuZGVuY2UKCldlIG5ldmVyIGNvbnNpZGVyZWQgdGhlIGFzc3VtcHRpb24gb2YgaW5kZXBlbmRlbnQgcmVxdWlyZWQgYnkgYm90aCBhICR0JC10ZXN0IGFuZCBsaW5lYXIgcmVncmVzc2lvbi4gIERvIHdlIHRydWx5IGhhdmUgaW5kZXBlbmRlbnQgc2FtcGxlcyBpbiB0aGlzIGNhc2U/ICBObyEgIFNpbmNlIHdlIGhhdmUgZmVtYWxlIGFuZCBtYWxlIHZhbHVlcyBmcm9tIHRoZSBzYW1lIGNvdW50cmllcywgb3VyIGRhdGEgaXMgcmVhbGx5IHdoYXQgd2Ugd291bGQgY2FsbCAicGFpcmVkIi4gVGhlIG1hbGUgYW5kIGZlbWFsZSBkaWV0IHZhbHVlcyBmcm9tIHRoZSBzYW1lIGNvdW50cnkgYXJlIG1vc3QgbGlrZWx5IHJlbGF0ZWQgdG8gZWFjaCBhbm90aGVyIGJlY2F1c2Ugb2YgY3VsdHVyYWwgZWZmZWN0cyBvbiBkaWV0LiAgVGhpcyBtZWFucyB0aGUgYXNzdW1wdGlvbiBvZiBpbmRlcGVuZGVuY2UgZm9yIHRoZSBpbmRlcGVuZGVudCBzYW1wbGVzICR0JC10ZXN0IGlzIHZpb2xhdGVkLCBhcyBpcyB0aGUgaW5kZXBlbmRlbmNlIGFzc3VtcHRpb24gZm9yIGxpbmVhciByZWdyZXNzaW9uLiAgCgpXZSBjYW4gYWRkcmVzcyB0aGlzIGJ5IGRvaW5nIGEgKnBhaXJlZCogJHQkLXRlc3QgaW5zdGVhZCBvZiBhbiBpbmRlcGVuZGVudCAkdCQtdGVzdCBhbmQgYnkgYWNjb3VudGluZyBmb3IgY291bnRyeSBpbiBvdXIgbGluZWFyIG1vZGVsIGJ5IGFkZGluZyBpdCB0byBvdXIgbW9kZWwgYXMgd2hhdCB3ZSBjYWxsIGEgKmZpeGVkIGVmZmVjdCouICAgCgojIyMgUGFpcmVkICR0JC10ZXN0IGFuZCBsaW5lYXIgbW9kZWwgd2l0aCBmaXhlZCBlZmZlY3RzCgpOb3cgd2lsbCBwZXJmb3JtIHRoZSBwYWlyZWQgdmVyc2lvbnMgb2Ygb3VyIGFuYWx5c2lzLiBUaGlzIGlzIHZlcnkgZWFzeSB0byBkbyB3aXRoIHRoZSBgdC50ZXN0KClgIGZ1bmN0aW9uLCBieSBzaW1wbHkgdXNpbmcgdGhlIGBwYWlyZWRgIGFyZ3VtZW50IGFuZCBzZXR0aW5nIGl0IGVxdWFsIHRvIGBUUlVFYC4KCkhvd2V2ZXIsIG91ciBkYXRhIG5lZWRzIHRvIGJlIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm0gdG8gZG8gdGhlIHBhaXJlZCB0ZXN0LCBzaW5jZSB3ZSBoYXZlIHRvIHRlbGwgYFJgIHdoaWNoIHZhbHVlcyBuZWVkIHRvIGJlIHBhaXJlZCB0b2dldGhlci4gIEluc3RlYWQgb2Ygb25lIGxvbmcgZGF0YXNldCB3aXRoIGRpZmZlcmVudCByb3dzIGZvciBtYWxlcyBhbmQgZmVtYWxlcywgd2Ugd2lsbCBuZWVkIHNlcGFyYXRlIGNvbHVtbnMgZm9yIHRoZSBtYWxlIGFuZCBmZW1hbGUgdmFsdWVzLiAgU28gd2UgbmVlZCB0byBtYWtlIG91ciBkYXRhc2V0ICp3aWRlciouICBXZSBjYW4gZG8gdGhhdCB1c2luZyB0aGUgYHBpdm90X3dpZGVyKClgIGZ1bmN0aW9uIG9mICB0aGUgYHRpZHlyYCBwYWNrYWdlLiBUbyB1c2UgdGhpcyBmdW5jdGlvbiB3ZSBzcGVjaWZ5IHRoZSB2YWx1ZXMgdGhhdCB3ZSB3YW50IHRvIHNlcGFyYXRlIGludG8gbW9yZSB2YXJpYWJsZXMgdXNpbmcgdGhlIGB2YWx1ZXNfZnJvbWAgYXJndW1lbnQgYW5kIHdlIHVzZSB0aGUgYG5hbWVzX2Zyb21gIGFyZ3VtZW50IHRvIHNwZWNpZnkgaG93IHdlIHdhbnQgdG8gc2VwYXJhdGUgdGhlc2Ugb3RoZXIgdmFyaWFibGVzLiBJbiB0aGlzIGNhc2Ugd2Ugd2lsbCBtYWtlIGEgbWFsZSBhbmQgZmVtYWxlIHZlcnNpb24gb2YgYWxsIHRoZSBvdGhlciB2YXJpYWJsZXMgc3BlY2lmaWVkLgoKYGBge3J9CndpZGVfZGlldCA8LSBkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gYyhjb250YWlucygicGVyY2VudCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdF9hY2hpZXZlZCksIAogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBzZXgpCgpnbGltcHNlKHdpZGVfZGlldCkKCiNUaGUgb2xkZXIgZnVuY3Rpb24gdGlkeXI6OnNwcmVhZCgpIHdvdWxkIG5vdCBhbGxvdyBmb3IgbXVsdGlwbGUgY29sdW1ucy92YXJpYWJsZXMgCmBgYAoKWW91IGNhbiBzZWUgd2Ugbm93IGhhdmUgYSBgUmVsYXRpdmVfUGVyY2VudF9NYWxlYCB2YXJpYWJsZSBhbmQgYSBgUmVsYXRpdmVfUGVyY2VudF9GZW1hbGVgIHZhcmlhYmxlLiAgV2UgY2FuIHVzZSB0aGVzZSB0d28gdmFyaWFibGVzIGluIG91ciBwYWlyZWQgJHQkLXRlc3QuICBTaW5jZSB0aGUgcGFpcmVkIHZlcnNpb24gb2YgdGhlICR0JC10ZXN0IGRvZXNuJ3QgdGFrZSBhIGBkYXRhPWAgYXJndW1lbnQsIHdlIHdpbGwgcHVsbCB0aGUgYXBwcm9wcmlhdGUgdmFyaWFibGVzIGZyb20gb3VyIGRhdGEgYSBsaXR0bGUgYml0IGRpZmZlcmVudGx5LCB1c2luZyB0aGUgYHB1bGwoKWAgZnVuY3Rpb24uCmBgYHtyfQp0LnRlc3QobG9nMTAocHVsbChmaWx0ZXIod2lkZV9kaWV0LCBmb29kID09ICJyZWQgbWVhdCIpLAogICAgICAgICAgICAgICAgICBSZWxhdGl2ZV9QZXJjZW50X01hbGUpKSwgCiAgICAgICBsb2cxMChwdWxsKGZpbHRlcih3aWRlX2RpZXQsIGZvb2QgPT0gInJlZCBtZWF0IiksCiAgICAgICAgICAgICAgICAgIFJlbGF0aXZlX1BlcmNlbnRfRmVtYWxlKSksCiAgICAgICB2YXIuZXF1YWwgPSBUUlVFLCBwYWlyZWQgPSBUUlVFKQpgYGAKCkhlcmUgYW4gZXN0aW1hdGVkIG1lYW4gZGlmZmVyZW5jZSAoTWFsZXMgLSBGZW1hbGVzKSBvZiAwLjE4LCBhbmQgdGhhdCB0aGlzIGlzIGNvbnNpZGVyZWQgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgdGhhbiAwIGR1ZSB0byBhIHZlcnkgc21hbGwgJHAkLXZhbHVlLiAgWW91IGNhbiBhbHNvIHNlZSB0aGF0IG5vdyBvdXIgZGVncmVlcyBvZiBmcmVlZG9tIGFyZSAxOTQsIHdoaWNoIG1ha2VzIHNlbnNlIGJlY2F1c2Ugd2l0aCBwYWlyZWQgc2FtcGxlcyB3ZSBhcmUgb25seSBlc3RpbWF0aW5nIG9uZSBwYXJhbWV0ZXIgKHRoZSBtZWFuIGRpZmZlcmVuY2UpIGJhc2VkIG9uIGRhdGEgb24gMTk1IGRpZmZlcmVuY2VzIGZvciBlYWNoIGNvdW50cnkuIFNvICRkZiA9IG4gLSBcIyBcIHBhcmFtZXRlcnMgPSAxOTUgLTEgPSAxOTQkLgoKVGhlIHBhaXJlZCB2ZXJzaW9uIG9mIHRoZSBsaW5lYXIgbW9kZWwgaXMgYSBiaXQgbW9yZSBjb21wbGV4LiBJbiB0aGlzIGNhc2Ugd2Ugd2lsbCBhZGQgYW5vdGhlciB0ZXJtIGluIG91ciBtb2RlbCB0byBldmFsdWF0ZSB0aGUgaW5mbHVlbmNlIG9mIGBzZXhgIG9uIGBSZWxhdGl2ZV9QZXJjZW50YCBjb25zdW1wdGlvbiB3aGlsZSBrZWVwaW5nIHRoZSBjb3VudHJ5IGlkZW50aXR5IGZpeGVkIG9yIGNvbnN0YW50LCBvciBpbiBvdGhlciB3b3JkcyBjb250cm9sbGluZy9hZGp1c3RpbmcgZm9yIGNvdW50cnkuIFdlIGNhbiB1c2UgdGhlICBgK2AgdG8gYWRkIHRoaXMgYWRkaXRpb25hbCB0ZXJtLiBOb3cgdGhhdCB3ZSBoYXZlIG11bHRpcGxlIGNvdmFyaWF0ZS9leHBsYW5hdG9yeSB2YXJpYWJsZSB0ZXJtcywgd2Ugd291bGQgY2FsbCB0aGlzIGEgKiptdWx0aXZhcmlhYmxlIGxpbmVhciByZWdyZXNzaW9uKiouCgpTbyBub3cgb3VyIG1vZGVsIGluIHdvcmRzIHdpbGwgYmU6IAoKTWVhbiByZWxhdGl2ZSBjb25zdW1wdGlvbiBvZiByZWQgbWVhdCBpcyBkZXBlbmRlbnQgb24gc2V4IGFuZCBjb3VudHJ5LiBPciBpbiBvdGhlciB3b3Jkcywgc2V4IGFuZCBsb2NhdGlvbiBpbmZsdWVuY2UgdGhlIGNvbnN1bXB0aW9uIG9mIHJlZCBtZWF0IGFyb3VuZCB0aGUgd29ybGQuCgpUaGVuIHRoZSBjb2VmZmljaWVudCBmb3IgYHNleGAgd2lsbCBiZSBkaWZmZXJlbnQgZnJvbSB3aGF0IHdlIGhhZCBpbiBvdXIgcHJldmlvdXMgYGxtKClgIG1vZGVsLCBhcyBpdCB3aWxsIGJlIGNhbGN1bGF0ZWQgd2hpbGUga2VlcGluZyBgbG9jYXRpb25fbmFtZWAgb3IgdGhlIGNvdW50cnkgd2hlcmUgdGhlIGNvbnN1bXB0aW9uIHZhbHVlIHdhcyBvYnRhaW5lZCBmaXhlZCwgb3IgaW4gb3RoZXIgd29yZHMgImNvbnRyb2xsaW5nIGZvciBgbG9jYXRpb25fbmFtZWAuIiBUaGlzIHdpbGwgYWxzbyByZXN1bHQgaW4gb3V0cHV0IGZvciBlYWNoIG9mIHRoZSBjb3VudHJpZXMuIFRoZSBbY29lZmZpY2llbnRzXShodHRwczovL3d3dy50aGVhbmFseXNpc2ZhY3Rvci5jb20vaW50ZXJwcmV0aW5nLXJlZ3Jlc3Npb24tY29lZmZpY2llbnRzLyl7dGFyZ2V0PSJfYmxhbmsifSBoZXJlIHJlcHJlc2VudCB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGluIGNvbnN1bXB0aW9uIHZhbHVlIGZvciBlYWNoIGNvdW50cnkgY29tcGFyZWQgdG8gdGhlIHJlZmVyZW5jZSBjb3VudHJ5IG9mIEFmZ2hhbmlzdGFuLCB3aGlsZSBhY2NvdW50aW5nIGZvciBzZXguCgpUaGlzIG5vdyBzaG91bGQgbWVldCB0aGUgYXNzdW1wdGlvbiBvZiBpbmRlcGVuZGVuY2UgZm9yIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwsIHNpbmNlIG9ic2VydmF0aW9ucyB3aWxsIGJlIGluZGVwZW5kZW50IGNvbmRpdGlvbmFsIGFuIHRoZSBjb3ZhcmlhdGVzIG9mIHNleCBhbmQgY291bnRyeS4KCkxldCdzIGZpdCB0aGlzIG1vZGVsIGFuZCBsb29rIGF0IHRoZSByZXN1bHRzLgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBsbShsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSB+IHNleCArIGxvY2F0aW9uX25hbWUsIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKYGBgCiMjIyMKCkZpcnN0IGxldCdzIGxvb2sgYXQgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudCBmb3IgdGhlIGBzZXhNYWxlYCB2YXJpYWJsZSwgd2hpY2ggaXMgMC4xOC4gIFRoaXMgY2FuIGJlIGludGVycHJldGVkIGFzIHRoZSBkaWZmZXJlbmNlIGluIG1lYW4gbG9nIHJlbGF0aXZlIHBlcmNlbnQgY29uc3VtcHRpb24gYmV0d2VlbiBtYWxlcyBhbmQgZmVtYWxlcywgaG9sZGluZyBjb3VudHJ5IGNvbnN0YW50LiAgU28gY29tcGFyaW5nIG1hbGVzIHRvIGZlbWFsZXMgd2l0aGluIHRoZSBzYW1lIGNvdW50cnkuICBOb3RpY2UgdGhpcyBpcyB0aGUgc2FtZSBlc3RpbWF0ZWQgZGlmZmVyZW5jZSB3ZSBmb3VuZCBmcm9tIG91ciBwYWlyZWQgJHQkLXRlc3QhICBUaGUgJHAkLXZhbHVlIGZvciB0aGlzIGNvZWZmaWNpZW50IGFsc28gbWF0Y2hlcyB0aGUgJHAkLXZhbHVlIGZyb20gdGhlIHBhaXJlZCAkdCQtdGVzdC4KCllvdSBjYW4gYWxzbyBzZWUgZnJvbSB0aGlzIG91dHB1dCB0aGF0IHdlIGhhdmUgYSBjb2VmZmljaWVudCBmb3IgZXZlcnkgY291bnRyeSBleGNlcHQgQWZnaGFuaXN0YW4sIHdoaWNoIGlzIG91ciByZWZlcmVuY2UgY291bnRyeS4gIFRoZXNlIGNvZWZmaWNpZW50cyBjb21wYXJlIHRoZSBjb3VudHJ5IHRvIHRoYXQgcmVmZXJlbmNlLiAgU28gdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudCBmb3IgYGxvY2F0aW9uX25hbWVBbGJhbmlhYCwgMC40NCwgY2FuIGJlIGludGVycHJldGVkIGFzIHRoZSBkaWZmZXJlbmNlIGluIG1lYW4gbG9nIHJlbGF0aXZlIHBlcmNlbnQgY29uc3VtcHRpb24gYmV0d2VlbiBBbGJhbmlhIGFuZCBBZmdoYW5pc3RhbiwgaG9sZGluZyBzZXggY29uc3RhbnQuICBTbyBjb21wYXJpbmcgQWxiYW5pYSB0byBBZmdoYW5pc3RhbiB3aXRoaW4gbWFsZXMgb3IgY29tcGFyaW5nIEFsYmFuaWEgdG8gQWZnaGFuaXN0YW4gd2l0aGluIGZlbWFsZXMuCgpGaW5hbGx5LCB5b3UgbWlnaHQgbm90aWNlIHRoYXQgdGhlIG51bWJlciBvZiByZXNpZHVhbCBkZWdyZWVzIG9mIGZyZWVkb20gZm9yIHRoaXMgcmVncmVzc2lvbiBpcyAxOTQsIGp1c3QgYXMgaW4gdGhlIHBhaXJlZCAkdCQtdGVzdC4gIFRoaXMgbWFrZXMgc2Vuc2Ugc2luY2Ugd2UgaGF2ZSB0byBlc3RpbWF0ZSBhIGNvZWZmaWNpZW50IGZvciAxOTQgY291bnRyaWVzIChhbGwgZXhjZXB0IEFmZ2hhbmlzdGFuKSBhcyB3ZWxsIGFzIGEgY29lZmZpY2llbnQgZm9yIHNleCBhbmQgYW4gaW50ZXJjZXB0LiAgU28gd2UgaGF2ZToKCiQkZGYgPSBuIC0gIyBwYXJhbWV0ZXJzIGVzdGltYXRpbmcgPSAzOTAgLSAxOTQgLSAyID0gMTk0JCQgCgpXZSBzaG91bGQgYWxzbyBjaGVjayB0aGUgcmVzaWR1YWwgcGxvdHMgZm9yIHRoaXMgZml4ZWQgZWZmZWN0cyByZWdyZXNzaW9uIG1vZGVsLgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG0obG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBzZXggKyBsb2NhdGlvbl9uYW1lLCBkYXRhID0gLikgJT4lCiAgcGxvdCh3aGljaCA9IDE6MykKYGBgCgpUaGVzZSByZXNpZHVhbCBwbG90cyBsb29rIG11Y2ggYmV0dGVyIHRoYW4gb3VyIHByZXZpb3VzIHBsb3RzLiAgVGhpcyBbZ3VpZGVdKGh0dHBzOi8vZGF0YS5saWJyYXJ5LnZpcmdpbmlhLmVkdS9kaWFnbm9zdGljLXBsb3RzLykgcHJvdmlkZXMgbW9yZSBpbmZvcm1hdGlvbiBvbiBob3cgdG8gaW50ZXJwcmV0IHRoZXNlIHJlc2lkdWFsIGRpYWdub3N0aWMgcGxvdHMuCgpCYXNlZCBvbiBvdXIgW1EtUSBwbG90XShodHRwOi8vb25saW5lc3RhdGJvb2suY29tLzIvYWR2YW5jZWRfZ3JhcGhzL3EtcV9wbG90cy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LCB3ZSBhcHBlYXIgdG8gaGF2ZSBzb21lIG91dGxpZXJzIHBlcmhhcHMgYXQgdGhlIGV4dHJlbWUgZW5kcyBvZiBvdXIgdGFpbHMgYnV0IG92ZXJhbGwgdGhlIHJlc2lkdWFscyBsb29rIGZhaXJseSBub3JtYWwuIFRoZSBbcmVzaWR1YWwgdnMgZml0dGVkIHBsb3RdKGh0dHBzOi8vb25saW5lLnN0YXQucHN1LmVkdS9zdGF0NDYyL25vZGUvMTE4Lyl7dGFyZ2V0PSJfYmxhbmsifSBzaG93cyB1cyBpZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gb3VyIG91dGNvbWUgdmFyaWFibGUgYW5kIG91ciBwcmVkaWN0b3JzIGxvb2tzIGxpbmVhciwgaWYgdGhlcmUgaXMgdW5lcXVhbCBlcnJvciB2YXJpYW5jZSBiZXR3ZWVuIGdyb3VwcywgYW5kIGlmIHRoZXJlIGFyZSBwb3NzaWJsZSBvdXRsaWVycy4gSWRlYWxseSB0aGlzIHNob3VsZCBsb29rIGxpa2UgYSBiYW5kIG9mIHBvaW50cyBlcXVhbGx5IGNlbnRlcmVkIGFyb3VuZCB6ZXJvLiBIZXJlIGFyZSBbZXhhbXBsZXNdKGh0dHA6Ly9kb2NzLnN0YXR3aW5nLmNvbS9pbnRlcnByZXRpbmctcmVzaWR1YWwtcGxvdHMtdG8taW1wcm92ZS15b3VyLXJlZ3Jlc3Npb24vKXt0YXJnZXQ9Il9ibGFuayJ9IG9mIHRoZXNlIHBsb3RzIHRoYXQgbWlnaHQgc2hvdyBpc3N1ZXMgb2YgY29uY2Vybi4gCgpPdmVyYWxsIG91ciBwbG90IGxvb2tzIGZhaXJseSBnb29kLiBUaGUgc2hhcGUgb2Ygb3VyIGRhdGEgbG9va3MgZmFpcmx5IGxpbmVhciAodGhlIHJlc2lkdWFscyBkb24ndCBhcHBlYXIgdG8gaGF2ZSBhIHNoYXBlIG90aGVyIHRoYW4gYSBiYW5kIG9yIGxpbmUpLCB0aGVyZSBkb2VzIG5vdCBhcHBlYXIgdG8gYmUgYW55IGV4dHJlbWUgb3V0bGllcnMgKG5vIGRhdGEgcG9pbnRzIGFyZSBlc3BlY2lhbGx5IGZhciBhd2F5KSBhbmQgdGhlIHBvaW50cyBoYXZlIHRoZSBzYW1lIGdlbmVyYWwgcmFuZ2UgYXJvdW5kIHRoZSBsaW5lIGZvciB0aGUgdmFyaW91cyBmaXR0ZWQgdmFsdWVzLiBUaGVyZSBhcmUgYSBmZXcgcG9pbnRzIHdpdGggd2lkZXIgcmVzaWR1YWxzIGF0IHRoZSBoaWdoZXIgZml0dGVkIHZhbHVlcywgYnV0IG92ZXJhbGwgdGhpcyBsb29rcyBxdWl0ZSByZWFzb25hYmxlLiAKCk91ciBbc2NhbGUtbG9jYXRpb24gcGxvdF0oaHR0cHM6Ly9ib29zdGVkbWwuY29tLzIwMTkvMDMvbGluZWFyLXJlZ3Jlc3Npb24tcGxvdHMtc2NhbGUtbG9jYXRpb24tcGxvdC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGFsc28gc2hvd3MgdXMgdGhhdCBvdXIgdmFyaWFuY2UgbG9va3MgZmFpcmx5IGVxdWFsIGFjcm9zcyBncm91cHMgYXMgb3VyIHZhbHVlcyBzaG93IGEgcmVsYXRpdmVseSBldmVuIHNwcmVhZC4gQSBsYXJnZXIgIGJlbmQgaW4gdGhlIGxpbmUgd291bGQgaW5kaWNhdGUgbW9yZSB2YXJpYXRpb24gaW4gdGhlIHZhcmlhbmNlIGFjcm9zcyBvdXIgaW5kZXBlbmRlbnQgdmFyaWFibGUgZ3JvdXBzIGFsc28ga25vd24gYXMgW2hldGVyb3NjZWRhc3RpY2l0eV0oaHR0cHM6Ly9zdGF0aXN0aWNzYnlqaW0uY29tL3JlZ3Jlc3Npb24vaGV0ZXJvc2NlZGFzdGljaXR5LXJlZ3Jlc3Npb24vKXt0YXJnZXQ9Il9ibGFuayJ9LiBUaGVyZSBpcyBvbmx5IGEgc2xpZ2h0IGJlbmQgaW4gdGhlIGxpbmUgZm9yIG91ciBkYXRhIHN1Z2dlc3RpdmUgb2YgW2hvbW9zY2VkYXN0aWNpdHkgXShodHRwczovL3d3dy5zdGF0aXN0aWNzc29sdXRpb25zLmNvbS9ob21vc2NlZGFzdGljaXR5Lyl7dGFyZ2V0PSJfYmxhbmsifS4gU28gb3VyIGFzc3VtcHRpb25zIGxvb2sgcHJldHR5IGdvb2Q6CgoxKSBMaW5lYXIgLSB0aGUgcmVsYXRpb25zaGlwIGFwcGVhcnMgdG8gYmUgZmFpcmx5IGxpbmVhciAKMikgSW5kZXBlbmRlbmNlIC0gbm93IHRoYXQgd2UgaGF2ZSB0YWtlbiBjYXJlIG9mIHRoZSBsb2NhdGlvbiBzdHJ1Y3R1cmUgaW4gb3VyIGRhdGEsIG91ciBzYW1wbGVzIGFyZSBpbmRlcGVuZGVudAozKSBOb3JtYWxpdHkgLSB0aGUgcmVzaWR1YWxzIGFwcGVhciB0byBiZSBmYWlybHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYW5kIHdlIGhhdmUgYSBsYXJnZSBudW1iZXIgb2Ygc2FtcGxlcyB0byBoZWxwIGFjY291bnQgZm9yIG1pbm9yIHZpb2xhdGlvbnMKNCkgRXF1YWwgdmFyaWFuY2UgLSB0aGUgdmFyaWFuY2UgaW4gdGhlIHJlc2lkdWFscyBhcHBlYXIgdG8gYmUgZmFpcmx5IGVxdWFsIGFjcm9zcyB0aGUgZ3JvdXBzIG9mIHRoZSBpbmRlcGVuZGVudC9wcmVkaWN0b3IgdmFyaWFibGVzCgoKIyMjIFBhaXJlZCAkdCQtdGVzdCBhbmQgbGluZWFyIG1vZGVsIHdpdGggbWl4ZWQgZWZmZWN0cyAKClRvICJwYWlyIiBvdXIgZGF0YSB1c2luZyBmaXhlZCBlZmZlY3RzIGNvc3QgdXMgYW4gYWRkaXRpb25hbCAxOTQgdmFyaWFibGVzIGluIG91ciByZWdyZXNzaW9uIG1vZGVsLCBvbmUgZm9yIGVhY2ggY291bnRyeSBleGNlcHQgQWZnaGFuaXN0YW4uICBBbHRlcm5hdGl2ZWx5LCB3ZSBjYW4gcGVyZm9ybSBhIHNsaWdodGx5IGRpZmZlcmVudCB0eXBlIG9mIHJlZ3Jlc3Npb24gdGhhdCBzdGlsbCBhY2NvdW50cyBmb3IgdGhlIHBhaXJlZCBzdHJ1Y3R1cmUgaW4gdGhlIGRhdGEuCgpJbiB0aGlzIGNhc2Ugd2Ugd2lsbCB1c2UgdGhlIGBsbWVyKClgIGZ1bmN0aW9uIG9mIHRoZSBgbG1lNGAgcGFja2FnZS4gIFRoaXMgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIGZpdCB3aGF0IGlzIGNhbGxlZCBhIFtsaW5lYXIgbWl4ZWQgZWZmZWN0cyByZWdyZXNzaW9uIG1vZGVsXShodHRwczovL291cmNvZGluZ2NsdWIuZ2l0aHViLmlvL3R1dG9yaWFscy9taXhlZC1tb2RlbHMvKXt0YXJnZXQ9Il9ibGFuayJ9LiBXZSB3aWxsIGFsc28gdXNlIHRoZSBgbG1lclRlc3RgIHBhY2thZ2UsIHNpbmNlIHRoaXMgYWRkcyB0ZXN0IHN0YXRpc3RpY3MgYW5kICRwJC12YWx1ZXMgdG8gdGhlIGxpbmVhciBtaXhlZCBlZmZlY3RzIG1vZGVsIG91dHB1dC4gIAoKVGhpcyB0eXBlIG9mIHJlZ3Jlc3Npb24gaXMgY2FsbGVkICoqbWl4ZWQqKiBiZWNhdXNlIGl0IGNvbnRhaW5zIGJvdGggKipmaXhlZCoqIGFuZCAqKnJhbmRvbSoqIGVmZmVjdHMuICBUaGVyZSBhcmUgbWFueSBkaWZmZXJlbnQgZGVmaW5pdGlvbnMgZm9yICoqZml4ZWQqKiBhbmQgKipyYW5kb20qKiBlZmZlY3RzIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyBjb25jZXB0dWFsbHkgY29tcGxleCBhbmQgY29udGV4dCBzcGVjaWZpYy4gCgpIb3dldmVyIGluIHNpbXBsaXN0aWMgdGVybXMsICoqZml4ZWQgZWZmZWN0cyoqIGFyZSBnZW5lcmFsbHkgc3BlYWtpbmcgdGhlIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCB0aGF0IHdlIGhhdmUgcmVhc29uIHRvIGJlbGlldmUgZXhwbGFpbiBvciBwcmVkaWN0IHRoZSBvdXRjb21lIG9yIHJlc3BvbnNlIHZhcmlhYmxlLCB3aGlsZSByYW5kb20gZWZmZWN0cyBhcmUgdGhvc2UgdGhhdCBtYXkgaW50cm9kdWNlIGFkZGl0aW9uYWwgdmFyaWFuY2UgaW4gdGhlIGluZmx1ZW5jZSBvZiB0aG9zZSBwcmVkaWN0b3IgdmFyaWFibGVzIG9uIHRoZSBvdXRjb21lIHZhcmlhYmxlLiBGb3IgZXhhbXBsZSwgdGhleSBtYXkgcHJvdmlkZSBpbmZvcm1hdGlvbiBhYm91dCAqKmdyb3VwIG9yIGJhdGNoIHN0cnVjdHVyZXMqKiB3aXRoaW4gdGhlIGRhdGEuICAKCkluIG91ciBjYXNlLCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgaW5mbHVlbmNlIG9mIGBzZXhgIG9uIHRoZSBjb25zdW1wdGlvbiBvZiByZWQgbWVhdCwgaG93ZXZlciB0aGUgaWRlbnRpdHkgb2YgdGhlIGNvdW50cnkgd2hlcmUgdGhlIG1hbGUgYW5kIGZlbWFsZSBjb25zdW1wdGlvbiB2YWx1ZXMgd2VyZSBvYnRhaW5lZCBtYXkgaW5mbHVlbmNlIHRoaXMgcmVsYXRpb25zaGlwIGFuZCB3ZSB3b3VsZCBsaWtlIHRvIGNvbnRyb2wgZm9yIHRoYXQuIFdlIGRvbid0IHdhbnQgdG8gbW9kZWwgZm9yIGBsb2NhdGlvbl9uYW1lYCBpdHNlbGYsIGJ1dCBqdXN0IG1vZGVsIGl0J3MgaW5mbHVlbmNlIG9uIHRoZSByZWxhdGlvbnNoaXAgb2YgYHNleGAgb24gY29uc3VtcHRpb24gb2YgcmVkIG1lYXQuIEluIG90aGVyIHdvcmRzLCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBnZXR0aW5nIGEgc2Vuc2Ugb2YgaG93IHNleCBpbmZsdWVuY2VzIGNvbnN1bXB0aW9uIHJhdGVzIGluIGdlbmVyYWwgYW5kIHdlIHdhbnQgdG8gYWNjb3VudCBmb3IgdGhlIHBhaXJlZCBzdHJ1Y3R1cmUgd2l0aGluIG91ciBkYXRhLCB0aGUgZmFjdCB0aGF0IHdlIGhhdmUgY29ycmVzcG9uZGluZyBjb25zdW1wdGlvbiB2YWx1ZXMgZm9yIHRoZSB0d28gc2V4ZXMgZnJvbSBkaWZmZXJlbnQgY291bnRyaWVzLiBUaGUgbm90YXRpb24gZm9yIGluY2x1ZGluZyBhIHJhbmRvbSBlZmZlY3QgbGlrZSB0aGlzIGlzICBgMSB8IHZhcmlhYmxlX25hbWVgLiBUaGUgb25lIGluZGljYXRlcyBhIHZhcnlpbmctaW50ZXJjZXB0IGdyb3VwIGVmZmVjdCwgaW4gb3RoZXIgd29yZHMgd2UgZXhwZWN0IHRoYXQgdGhlIGludGVyY2VwdCBtYXkgdmFyeSBmb3IgZWFjaCB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgaW5kaWNhdGVkIHRvIHRoZSByaWdodCBvZiB0aGUgYHxgLiBTbyBpbiBvdXIgY2FzZSwgdGhlIGludGVyY2VwdCAgKGxvZyByZWxhdGl2ZSBwZXJjZW50IGNvbnN1bXB0aW9uIHdoZW4gc2V4IGlzIGFzc2lnbmVkIHRvIHRoZSB6ZXJvIHZhbHVlIC0gZmVtYWxlKSBtYXkgYmUgZGlmZmVyZW50IGZvciBlYWNoIGNvdW50cnkuCgpMZXQncyBmaXQgYSBtaXhlZCBlZmZlY3RzIG1vZGVsIHRoYXQgaW5jbHVkZXMgYSBmaXhlZCBlZmZlY3QgZm9yIHNleCBhbmQgYSByYW5kb20gaW50ZXJjZXB0IGZvciBjb3VudHJ5OgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG1lcihsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSB+IHNleCArICgxIHwgbG9jYXRpb25fbmFtZSksIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKYGBgCgpIb3cgd291bGQgd2UgaW50ZXJwcmV0IHRoZSByZXN1bHRzIG9mIHRoaXMgbW9kZWw/IEFnYWluLCBsZXQncyBsb29rIGF0IHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnQgZm9yIHRoZSBgc2V4TWFsZWAgdmFyaWFibGUsIHdoaWNoIGlzIDAuMTguICBUaGlzIGNhbiBiZSBpbnRlcnByZXRlZCB0aGUgc2FtZSB3YXkgYXMgaW4gdGhlIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiwgYXMgdGhlIGRpZmZlcmVuY2UgaW4gbWVhbiBsb2cgcmVsYXRpdmUgcGVyY2VudCBjb25zdW1wdGlvbiBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzLiAgSG93ZXZlciwgaGVyZSB3ZSBoYXZlbid0IHZpb2xhdGVkIHRoZSBpbmRlcGVuZGVuY2UgYXNzdW1wdGlvbiBiZWNhdXNlIHdlIGFyZSBhY2NvdW50aW5nIGZvciB0aGUgcGFpcmVkIG5hdHVyZSBvZiB0aGUgZGF0YSB0aHJvdWdoIHRoZSByYW5kb20gZWZmZWN0IGZvciBjb3VudHJ5LiAgVGhlICR0JC1zdGF0aXN0aWMgYW5kICRwJC12YWx1ZSBmb3IgdGhpcyBjb2VmZmljaWVudCBhbHNvIG1hdGNoIHRob3NlIGZyb20gdGhlIHBhaXJlZCAkdCQtdGVzdCB3ZSBkaWQgYmVmb3JlOgpgYGB7cn0KdC50ZXN0KGxvZzEwKHB1bGwoZmlsdGVyKHdpZGVfZGlldCwgZm9vZCA9PSAicmVkIG1lYXQiKSwKICAgICAgICAgICAgICAgICAgUmVsYXRpdmVfUGVyY2VudF9NYWxlKSksIAogICAgICAgbG9nMTAocHVsbChmaWx0ZXIod2lkZV9kaWV0LCBmb29kID09ICJyZWQgbWVhdCIpLAogICAgICAgICAgICAgICAgICBSZWxhdGl2ZV9QZXJjZW50X0ZlbWFsZSkpLAogICAgICAgdmFyLmVxdWFsID0gVFJVRSwgcGFpcmVkID0gVFJVRSkKYGBgCgpOb3RpY2UgdGhhdCBpbiB0aGUgb3V0cHV0IGZvciB0aGUgbWl4ZWQgZWZmZWN0cyBtb2RlbCwgdGhlcmUgYXJlICoqbm90KiogY29lZmZpY2llbnRzIGZvciBlYWNoIGNvdW50cnksIGxpa2UgdGhlcmUgd2VyZSBpbiB0aGUgZml4ZWQgZWZmZWN0cyBtb2RlbC4gIFRoaXMgaXMgYmVjYXVzZSB3ZSBhcmUgbm90IGV4cGxpY2l0bHkgZXN0aW1hdGluZyBpbmRpdmlkdWFsIGNvdW50cnkgZWZmZWN0cyBpbiB0aGlzIG1vZGVsLiAgSW5zdGVhZCwgdGhlIGNvdW50cnkgZWZmZWN0IGlzIGNhcHR1cmVkIHRocm91Z2ggdGhlIGludGVyY2VwdCBpbiB0aGlzIG1vZGVsLiAgT3VyIGVzdGltYXRlZCBpbnRlcmNlcHQgaXMgMS44MCBhbmQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGlzIGludGVyY2VwdCBpcyAwLjM0IChzaG93biBpbiB0aGUgYFJhbmRvbSBlZmZlY3RzYCB0YWJsZSBpbiB0aGUgb3V0cHV0LikgIFdlIGNhbiBpbnRlcnByZXQgdGhpcyBhcyBzYXlpbmcgdGhhdCBlYWNoIGNvdW50cnkgaGFzIGFuIGludGVyY2VwdCB0aGF0IGNvbWVzIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggbWVhbiBvZiAxLjgwIGFuZCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAwLjM0LiAgU2luY2UgdGhlIGludGVyY2VwdCBpbiB0aGlzIG1vZGVsIHJlcHJlc2VudCB0aGUgbG9nIHJlbGF0aXZlIHBlcmNlbnQgY29uc3VtcHRpb24gZm9yIGZlbWFsZXMsIHRoaXMgZ2l2ZSB1cyBhbiBpZGVhIG9mIGhvdyBmZW1hbGUgY29uc3VtcHRpb24gdmFyaWVzIGFjcm9zcyBjb3VudHJpZXMgLS0gYXZlcmFnZSBsb2cgY29uc3VtcHRpb24gYWNyb3NzIGNvdW50cmllcyBpcyAxLjgwLCBidXQgdGhlcmUgaXMgdmFyaWFiaWxpdHkgZnJvbSBvbmUgY291bnRyeSB0byBhbm90aGVyLiAgQW5kIHRoZW4gdGhlIG1hbGUgbG9nIGNvbnN1bXB0aW9uIGlzLCBvbiBhdmVyYWdlLCAwLjE4IGhpZ2hlciB0aGFuIGZvciBmZW1hbGVzLgoKSXQgaXMgbW9yZSBjb21wbGljYXRlZCB0byBjYWxjdWxhdGUgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBpbiB0aGUgbWl4ZWQgZWZmZWN0IG1vZGVsIGFuZCBiZXlvbmQgdGhpcyBjYXNlIHN0dWR5LCBidXQgaXQgaXMgYmFzZWQgb24gdGhlIFtTYXR0ZXJ0aHdhaXRlIGZvcm11bGFdKGh0dHBzOi8vd3d3LnN0YXRpc3RpY3Nob3d0by5kYXRhc2NpZW5jZWNlbnRyYWwuY29tL3NhdHRlcnRod2FpdGUtZm9ybXVsYS8pe3RhcmdldD0iX2JsYW5rIn0gYW5kIHJlc3VsdHMgaW4gdGhlIHNhbWUgZGVncmVlcyBvZiBmcmVlZG9tLgoKRmluYWxseSwgbGV0cyBzZWUgd2hhdCBvdXIgcmVzaWR1YWwgcGxvdHMgbG9vayBsaWtlIGZvciB0aGlzIG1peGVkIGVmZmVjdHMgbW9kZWwuICBXZSBjYW4ndCB1c2UgdGhlIGBwbG90KClgIGZ1bmN0aW9uIHdpdGggYSBgbG1lcigpYCBtb2RlbCB0byBnZXQgYWxsIG9mIHRoZSBwbG90cyBhdCBvbmNlLCBidXQgd2UgY2FuIGNvbnN0cnVjdCBhIHJlc2lkdWFsIHZzLiBmaXR0ZWQgdmFsdWUgcGxvdCBhbmQgYSBRLVEgcGxvdCBvdXJzZWx2ZXM6CgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBsbWVyKGxvZzEwKFJlbGF0aXZlX1BlcmNlbnQpIH4gc2V4ICsgKDEgfCBsb2NhdGlvbl9uYW1lKSwgZGF0YSA9IC4pICU+JQogIHBsb3QoKQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBsbWVyKGxvZzEwKFJlbGF0aXZlX1BlcmNlbnQpIH4gc2V4ICsgKDEgfCBsb2NhdGlvbl9uYW1lKSwgZGF0YSA9IC4pICU+JQogIHJlc2lkKCkgJT4lCiAgcXFub3JtKCkKCmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG1lcihsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSB+IHNleCArICgxIHwgbG9jYXRpb25fbmFtZSksIGRhdGEgPSAuKSAlPiUKICByZXNpZCgpICU+JQogIHFxbGluZSgpCmBgYAoKTm90aWNlIHRoYXQgdGhlIHBsb3RzIGxvb2sgdmVyeSBzaW1pbGFyIHRvIHdoYXQgd2Ugc2F3IHdpdGggdGhlIGZpeGVkIGVmZmVjdHMgbW9kZWwuCgpXZSBzZWUgdGhhdCB0aGUgcGFpcmVkICR0JC10ZXN0LCB0aGUgZml4ZWQgZWZmZWN0cyBtb2RlbCBhZGp1c3RpbmcgZm9yIGNvdW50cnksIGFuZCB0aGUgbWl4ZWQgZWZmZWN0cyBtb2RlbCB3aXRoIGEgcmFuZG9tIGludGVyY2VwdCBmb3IgY291bnRyeSBhbGwgZ2l2ZSB0aGUgc2FtZSByZXN1bHRzIGluIHRoaXMgY2FzZS4gIFNvIHdoaWNoIHRlc3Qgc2hvdWxkIHdlIHVzZT8gIFRoZSBkZWNpc2lvbiBvZiB3aGljaCB0ZXN0IHRvIHBlcmZvcm0gZGVwZW5kcyBvbiB5b3VyIHF1ZXN0aW9uIG9mIGludGVyZXN0LiBJbiB0aGlzIGNhc2Ugd2Ugd2VyZSBwYXJ0aWN1bGFybHkgaW50ZXJlc3RlZCBpbiB0aGUgaW5mbHVlbmNlIG9mIGBzZXhgLCBzbyBzZXR0aW5nIGBsb2NhdGlvbl9uYW1lYCB0byBhIHJhbmRvbSBlZmZlY3QgcHJvdmlkZXMgdGhlIHNhbWUgbGV2ZWwgb2YgZGV0YWlsIGFib3V0IHNleCB3aXRob3V0IGFzIG11Y2ggaW5mb3JtYXRpb24gYWJvdXQgYGxvY2F0aW9uX25hbWVgLCBzbyB0aGF0IG1pZ2h0IGJlIGlkZWFsLiBBcyB3ZSBjYW4gc2VlLCB0aGUgcmVzdWx0cywgaW4gdGhpcyBjYXNlLCBhcmUgdGhlIHNhbWUuICBUaGUgYmVuZWZpdCBvZiB1c2luZyByZWdyZXNzaW9uIG92ZXIgYSBzaW1wbGUgcGFpcmVkICR0JC10ZXN0IHdvdWxkIGJlIHRoZSBhYmlsaXR5IHRvIGFkZCBvdGhlciBjb3ZhcmlhdGVzIHRvIG91ciBtb2RlbCBpZiB3ZSB3YW50ZWQgdG8gYWRqdXN0IGZvciBvdGhlciBjb3VudHJ5IGNoYXJhY3RlcmlzdGljcy4KCk92ZXJhbGwsIHRob3VnaCwgd2UgY2FuIGNvbmNsdWRlIGZyb20gdGhlc2UgdGVzdHMgdGhhdCB3ZSBoYXZlIGVub3VnaCBldmlkZW5jZSB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbWVhbiBjb25zdW1wdGlvbiBvZiBtYWxlcyBhbmQgZmVtYWxlcyAoIG9yIHRoYXQgYHNleGAgaGFzIG5vIGFzc29jaWF0aW9uIG9yIGluZmx1ZW5jZSBvbiByZWQgbWVhdCBjb25zdW1wdGlvbi4pICoqVGhlcmVmb3JlLCBpdCBhcHBlYXJzIHRoYXQgbWFsZXMgY29uc3VtZSBzaWduaWZpY2FudGx5IG1vcmUgcmVkIG1lYXQgdGhhbiBmZW1hbGVzIGdsb2JhbGx5LioqIAoKCiMjIyBBTmFseXNpcyBPZiBWQXJpYW5jZSAoQU5PVkEpIHRlc3QKCldlIGFyZSBhbHNvIGludGVyZXN0ZWQgaW4gdGhlIGluZmx1ZW5jZSBvZiBhZ2UgZ3JvdXAgb24gZGlldGFyeSBjb25zdW1wdGlvbiwgYnV0IGJlY2F1c2UgdGhlcmUgYXJlIDE1IGFnZSBncm91cHMgd2UgY2FuJ3QgYXNzZXNzIHRoZSBpbmZsdWVuY2Ugb2YgYWdlIGdyb3VwIG9uIGNvbnN1bXB0aW9uIHVzaW5nIHRoZSBwYWlyZWQgJHQkLXRlc3QsIGFzIHRoaXMgdGVzdCBjYW4gb25seSBjb21wYXJlIDIgZ3JvdXBzLiAKCklmIHdlIHdhbnRlZCB0byB0ZXN0IHRoZSBoeXBvdGhlc2lzIHRoYXQgdGhlcmUgYXJlIGFueSBhZ2UgZ3JvdXAgZGlmZmVyZW5jZXMsIHRoYXQgYXQgbGVhc3Qgb25lIG9mIHRoZSBncm91cHMgaXMgZGlmZmVyZW50IGZyb20gdGhlIG90aGVyczsgd2UgY291bGQgdXNlIGFuIFtBTk9WQSB0ZXN0XShodHRwOi8vb25saW5lc3RhdGJvb2suY29tLzIvYW5hbHlzaXNfb2ZfdmFyaWFuY2UvaW50cm8uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4gVGhpcyB0ZXN0IGFsbG93cyB1cyB0byBjb21wYXJlIG1lYW5zIG9mIDMgb3IgbW9yZSBncm91cHMgYnkgZXZhbHVhdGluZyB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRhdGEgd2l0aGluIHRoZSBncm91cHMgYW5kIGFtb25nIHRoZSBncm91cHMuIAoKT3VyIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IGFsbCBhZ2UgZ3JvdXBzIGhhdmUgZXF1YWwgbWVhbnM6CiQkIEhfMDogXG11X3sxfSA9IFxtdV97Mn0gPVxtdV97M309XG11X3s0fSA9IC4uLiBcbXVfezE1fSAkJAoKVGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgaXMgdGhhdCBhdCBsZWFzdCBvbmUgYWdlIGdyb3VwIG1lYW4gaXMgbm90IGVxdWFsIHRvIHRoZSBvdGhlcnMuCgoqKkltcG9ydGFudGx5KiosIGlmIHdlIHJlamVjdCB0aGUgbnVsbCwgd2UgKmRvIG5vdCBrbm93IHdoaWNoIGdyb3VwIG1lYW5zIGFyZSBkaWZmZXJlbnQgZnJvbSBvbmUgYW5vdGhlciouIFN1YnNlcXVlbnQgdGVzdGluZyBpcyByZXF1aXJlZCBpZiB3ZSB3YW50IHRvIGtub3cgdGhpcyBpbmZvcm1hdGlvbi4gSW4gdGhpcyBjYXNlIHdlIGNhbGwgdGhpcyB0eXBlIG9mIG5vbi1zcGVjaWZpYyBoeXBvdGhlc2lzIGFuICJvbW5pYnVzIiBoeXBvdGhlc2lzLgoKWW91IGNvdWxkIGFjdHVhbGx5IHBlcmZvcm0gYW4gQU5PVkEgdG8gY29tcGFyZSB0d28gbWVhbnMsIGJ1dCBpbiB0aGlzIGNhc2UgeW91IHdvdWxkIGdldCBhbiAkRiQtc3RhdGlzdGljIGluc3RlYWQgb2YgYSAkdCQtc3RhdGlzdGljIHdoaWNoIHdvdWxkIGJlIGVxdWl2YWxlbnQgdG8gJHReMiQuIEhvd2V2ZXIgaXQgaXMgbm90IGNvbnZlbnRpb25hbCB0byB1c2UgQU5PVkEgZm9yIG9ubHkgMiBtZWFucy4gVGhlICRGJC1zdGF0aXN0aWMgaXMgZGVyaXZlZCBmb3JtIHRoZSAkRiQtdGVzdCBpcyB1c2VkIGZvciBhIGZldyBkaWZmZXJlbnQgdHlwZSBvZiB0ZXN0cy4gSW4gdGhlIEFOT1ZBIHRoZSBGLXRlc3QgaXMgY2FsY3VsYXRlZCBhczoKCiQkRiA9IFxmcmFjeyAKdmFyaWFiaWxpdHlcIGJldHdlZW5cICB0aGUgXCBncm91cHN9eyAKdmFyaWFibGl0eVwgd2l0aGluXCB0aGUgXCBncm91cHN9JCQKClRoZSBsYXJnZXIgdGhlIHJhdGlvLCB0aGUgbGFyZ2VyIHRoZSB2YXJpYWJpbGl0eSBiZXR3ZWVuIHRoZSBncm91cHMsIHRodXMgdGhlIG1vcmUgbGlrZWx5IHRoYXQgdGhlIGRhdGEgZm9yIGVhY2ggZ3JvdXAgY29tZXMgZnJvbSBhIGRpZmZlcmVudCBkaXN0cmlidXRpb24gd2l0aCBkaWZmZXJlbnQgbWVhbnMsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgZ3JvdXBzIGFyZSBkaWZmZXJlbnQuCgpJdCB0dXJucyBvdXQgdGhhdCB0aGUgQU5PVkEgdGVzdCBpcyBhbHNvIGVxdWl2YWxlbnQgdG8gbGluZWFyIHJlZ3Jlc3Npb24uICBXZSB3aWxsIGRlbW9uc3RyYXRlIHRoaXMgYnkgZXZhbHVhdGluZyBob3cgdGhlIGNvbnN1bXB0aW9uIG9mIHJlZCBtZWF0IHZhcmllcyBieSBhZ2UgZ3JvdXAgdXNpbmcgYW4gQU5PVkEgYW5kIGEgbGluZWFyIHJlZ3Jlc3Npb24uCgpUaGlua2luZyBhYm91dCBob3cgd2Ugd2FudCB0byBrbm93IGlmIHJlZCBtZWF0IGNvbnN1bXB0aW9uIGRpZmZlcnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZyb20gdGhlIGxpbmVhciByZWdyZXNzaW9uIHBlcnNwZWN0aXZlLCB3ZSBjb3VsZCBhbHNvIGRlc2NyaWJlIG91ciBudWxsIGh5cG90aGVzaXMgYXM6CgpUaGVyZSBpcyBubyBpbmZsdWVuY2Ugb2YgYWdlIGdyb3VwIGlkZW50aXR5IG9uIGNvbnN1bXB0aW9uIG9yIHRoZXJlIGlzIG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFnZSBncm91cCBpZGVudGl0eSBhbmQgY29uc3VtcHRpb24uCgpBbmQgd2UgY291bGQgZGVzY3JpYmUgb3VyIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgYXM6CgpBZ2UgZ3JvdXAgaWRlbnRpdHkgZG9lcyBpbmZsdWVuY2UgY29uc3VtcHRpb24gb3IgZXhwbGFpbiBzb21lIG9mIHRoZSB2YXJpYXRpb24gaW4gY29uc3VtcHRpb24uCgojIyMjIEFOT1ZBIGFzc3VtcHRpb25zCgpUaGUgQU5PVkEgYXNzdW1wdGlvbnMgYXJlIHF1aXRlIHNpbWlsYXIgdG8gdGhlICR0JC10ZXN0IGFzc3VtcHRpb25zOgoKMSkgTm9ybWFsaXR5IG9mIHRoZSBkYXRhIGZvciBhbGwgdGVzdGVkIGdyb3VwcyAobGVzcyBvZiBhbiBpc3N1ZSBpZiB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyByZWxhdGl2ZWx5IGxhcmdlIHRvdGFsIG4gPiAzMCkKMikgRXF1YWwgdmFyaWFuY2UgYmV0d2VlbiB0aGUgZ3JvdXBzIC0gYWthIFtIb21vZ2VuZWl0eSBvZiBWYXJpYW5jZXMgYXNzdW1wdGlvbl0oaHR0cHM6Ly91Yy1yLmdpdGh1Yi5pby9hc3N1bXB0aW9uc19ob21vZ2VuZWl0eSl7dGFyZ2V0PSJfYmxhbmsifSAobWFrZSBzdXJlIHlvdSBkbyB0aGUgY29ycmVjdCB0ZXN0IGlmIHRoZSBkYXRhIGlzIG5vdCBub3JtYWwpCjMpIEluZGVwZW5kZW50IG9ic2VydmF0aW9ucwoKbGV0J3MgZXZhbHVhdGUgb3VyIGFzc3VtcHRpb25zIGZvciB0aGUgZ3JvdXBzIHdlIGFyZSBjb21wYXJpbmcsIHN0YXJ0aW5nIHdpdGggbm9ybWFsaXR5IHVzaW5nIFEtUSBwbG90cy4gIEZpcnN0IGxldCdzIG1ha2UgYGFnZV9ncm91cF9uYW1lYCBhIGZhY3RvcjoKCmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZV9hdCh2YXJzKGFnZV9ncm91cF9uYW1lKSwgZmFjdG9yKQpgYGAKCk5vdyBsZXQncyBsb29rIGF0IFEtUSBwbG90cyBvZiBib3RoIHJlbGF0aXZlIHBlcmNlbnQgY29uc3VtcHRpb24gYW5kIHRoZSBsb2ctdHJhbnNmb3JtZWQgdmVyc2lvbiBvZiB0aGlzIHZhcmlhYmxlOgpgYGB7cn0KYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGdncGxvdChhZXMoc2FtcGxlID0gUmVsYXRpdmVfUGVyY2VudCkpICsKICBmYWNldF93cmFwKH4gYWdlX2dyb3VwX25hbWUpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSkpICsKICBmYWNldF93cmFwKH4gYWdlX2dyb3VwX25hbWUpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpCmBgYAoKQWZ0ZXIgdHJhbnNmb3JtYXRpb24sIHRoZXNlIFEtUSBwbG90cyBsb29rIHByZXR0eSBnb29kLgoKTm93IGxldCdzIGxvb2sgYXQgdGhlIGFzc3VtcHRpb24gb2YgY29uc3RhbnQgdmFyaWFuY2UuIFRoZXJlIGFyZSBkaWZmZXJlbnQgd2F5cyB0byBhc3Nlc3MgdGhpcyBhc3N1bXB0aW9uIGFjcm9zcyBtb3JlIHRoYW4gdHdvIGdyb3Vwcy4gIFtCYXJ0bGV0dCdzIHRlc3RdKGh0dHBzOi8vd3d3Lml0bC5uaXN0Lmdvdi9kaXY4OTgvaGFuZGJvb2svZWRhL3NlY3Rpb24zL2VkYTM1Ny5odG0pe3RhcmdldD0iX2JsYW5rIn0gd29ya3Mgd2VsbCBpZiB0aGUgZGF0YSBhcHBlYXJzIHRvIGJlIHF1aXRlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCB3aGlsZSB0aGUgW0ZsaWduZXItS2lsbGVlbl0oaHR0cDovL3dpa2kuc3RhdC51Y2xhLmVkdS9zb2NyL2luZGV4LnBocC9BUF9TdGF0aXN0aWNzX0N1cnJpY3VsdW1fMjAwN19Ob25QYXJhbV9WYXJJbmRlcCl7dGFyZ2V0PSJfYmxhbmsifSB0ZXN0IGlzIG5vbnBhcmFtZXRyaWMgYW5kIGRvZXMgbm90IGFzc3VtZSBub3JtYWxpdHkgb2YgdGhlIGRhdGEuCgpXZSB3aWxsIHVzZSBhbm90aGVyIHBvcHVsYXIgdGVzdCwgW0xldmVuZSdzIHRlc3RdKGh0dHBzOi8vd3d3Lml0bC5uaXN0Lmdvdi9kaXY4OTgvaGFuZGJvb2svZWRhL3NlY3Rpb24zL2VkYTM1YS5odG0pe3RhcmdldD0iX2JsYW5rIn0sIHdoaWNoIGlzIG1vcmUgcm9idXN0IHRvIHZpb2xhdGlvbnMgb2Ygbm9ybWFsaXR5IHRoYW4gdGhlIEJhcnRsZXR0J3MgdGVzdCwgYnV0IG5vdCBhcyByb2J1c3QgYXMgdGhlIEZsaWduZXItS2lsbGVlbiB0ZXN0LiAgVGhlIG51bGwgaHlwb3RoZXNpcyBvZiB0aGlzIHRlc3QsIGFzIGZvciB0aGUgb3RoZXIgdHdvIHRlc3RzLCBpcyB0aGF0IHRoZSB2YXJpYW5jZXMgYXJlIGVxdWFsIGFjcm9zcyBhbGwgb2YgdGhlIGdyb3Vwcy4gIFRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIGlzIHRoYXQgYXQgbGVhc3Qgb25lIHBhaXIgb2YgZ3JvdXBzIGhhcyBkaWZmZXJlbnQgdmFyaWFuY2VzLiAgSW4gc3ltYm9scyB3ZSB3b3VsZCB3cml0ZSB0aGlzIGFzCgokJCBIXzA6IFxzaWdtYV8xXjIgPSBcc2lnbWFfMl4yID0gXHNpZ21hXzNeMiAuLi4gPSBcc2lnbWFfbl4yICQkCgphbmQKCiQkSF9hOlxzaWdtYV9pXjIgXG5lcSBcc2lnbWFfal4yICAgJCQKZm9yIGF0IGxlYXN0ICBvbmUgIHBhaXIgKCRpJCwkaiQpLgoKCldlIHdpbGwgdXNlIHRoZSBgbGV2ZW5lVGVzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYGNhcmAgcGFja2FnZSB0byBwZXJmb3JtcyBMZXZlbmUncyB0ZXN0LgoKYGBge3J9CmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBjYXI6OmxldmVuZVRlc3QobG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBhZ2VfZ3JvdXBfbmFtZSwgZGF0YSA9IC4pCmBgYAoKT3VyIGRhdGEgZG9lcyBub3QgYXBwZWFyIHRvIHZpb2xhdGUgdGhlIGhvbW9nZW5laXR5IG9mIHZhcmlhbmNlcyBhc3N1bXB0aW9uIGFzIG91ciAkcCQtdmFsdWUgd2FzIGdyZWF0ZXIgdGhhbiAwLjA1IGFuZCBzbyB3ZSB3b3VsZCBmYWlsIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIG9mIGVxdWFsIHZhcmlhbmNlcy4KCldlIGFscmVhZHkga25vdyB0aGF0IG91ciBpbmRlcGVuZGVuY2UgYXNzdW1wdGlvbiBpcyBub3QgbWV0LCBzaW5jZSB0aGUgZGF0YSBmb3IgdGhlIGRpZmZlcmVudCBhZ2UgZ3JvdXBzIGNvbWVzIGZyb20gdGhlIHNhbWUgY291bnRyaWVzLiAgV2Ugd2lsbCBhY2NvdW50IGZvciB0aGlzIGluIGxhdGVyIG1vZGVscywgYnV0IGZpcnN0IGxldCdzIGNvbXBhcmUgdGhlIHJlc3VsdHMgYmV0d2VlbiBBTk9WQSBhbmQgbGluZWFyIHJlZ3Jlc3Npb24gYXNzdW1pbmcgdGhlIGluZGVwZW5kZW5jZSBhc3N1bXB0aW9uIGlzIG1ldC4KCiMjIyMgQU5PVkEgYW5kIGxpbmVhciByZWdyZXNzaW9uCgpXZSBjYW4gdXNlIHRoZSBgYW92KClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RhdHNgIHBhY2thZ2UgdG8gcGVyZm9ybSBhbiBBTk9WQSB0ZXN0LiBXZSB3aWxsIGJlIHBlcmZvcm1pbmcgd2hhdCBpcyBjYWxsZWQgYSBbb25lLXdheSBBTk9WQV0oaHR0cDovL29ubGluZXN0YXRib29rLmNvbS8yL2FuYWx5c2lzX29mX3ZhcmlhbmNlL29uZS13YXkuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBiZWNhdXNlIHdlIG9ubHkgaGF2ZSBvbmUgaW5kZXBlbmRlbnQgdmFyaWFibGUgKGFnZSBncm91cCkuIFdlIHdpbGwgYWxzbyBwZXJmb3JtIGEgbGluZWFyIHJlZ3Jlc3Npb24gZm9yIGNvbXBhcmlzb24uCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgYW92KGxvZzEwKFJlbGF0aXZlX1BlcmNlbnQpIH4gYWdlX2dyb3VwX25hbWUsIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUgIAogIGxtKGxvZzEwKFJlbGF0aXZlX1BlcmNlbnQpIH4gYWdlX2dyb3VwX25hbWUsIGRhdGE9IC4pICU+JQogIHN1bW1hcnkoKQoKYGBgCiMjIyMKCgpXZSBjYW4gc2VlIHRoYXQgdGhlICRGJC1zdGF0aXN0aWMgKCRGJCB2YWx1ZSBpbiB0aGUgYGFvdigpYCBvdXRwdXQgYW5kIGF0IHRoZSBib3R0b20gb2YgdGhlIGBsbSgpYCBvdXRwdXQpIGlzIHRoZSBzYW1lIGZvciBib3RoIG1vZGVscyBhbmQgdGhlICRwJC12YWx1ZSBmb3IgdGhlICRGJC1zdGF0aXN0aWMgaXMgdGhlIHNhbWUhCgpXZSBhbHNvIHNlZSB0aGF0IHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gZm9yIHRoZSAkRiQtc3RhdGlzdGljIGlzIDE0LiBUaGlzIG1ha2VzIHNlbnNlIGJlY2F1c2Ugd2UgaGF2ZSAxNSBkaWZmZXJlbnQgYWdlIGdyb3VwcyBhbmQgZGVncmVlcyBvZiBmcmVlZG9tIGZvciB0aGUgJEYkLXN0YXRpc3RpYyBhcmUgY2FsY3VsYXRlZCBhcyAkZGYgPSBuIC0gMSQuIFNvIGluIG91ciBjYXNlOiAkZGYgPSAxNSAtMSQuCgoKVGhlIGRpZmZlcmVuY2UgaGVyZSBpcyB0aGF0IHdpdGggdGhlIGBsbSgpYCBtb2RlbCB3ZSBhbHNvIGdldCBpbmZvcm1hdGlvbiBhYm91dCBob3cgdGhlIGluZGl2aWR1YWwgYWdlIGdyb3VwcyBhcmUgYXNzb2NpYXRlZCB3aXRoIHRoZSBsb2cgcmVsYXRpdmUgcGVyY2VudCBjb25zdW1wdGlvbiBvZiByZWQgbWVhdC4gTm90aWNlIHRoYXQgaWYgd2UgbG9vayBhdCBhbGwgdGhlIGFnZSBncm91cHMgaW4gdGhlIGRhdGEKCmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lIAogIGRpc3RpbmN0KGFnZV9ncm91cF9uYW1lKQpgYGAKCndlIHNlZSB0aGF0IG91ciBgbG0oKWAgcmVzdWx0cyBhcmUgbWlzc2luZyBvbmUgb2YgdGhlIGFnZSBncm91cHMsIHRoZSBgMjUgdG8gMjlgIGFnZSBncm91cC4gVGhhdCBpcyBiZWNhdXNlIHRoaXMgaXMgdGhlICoqcmVmZXJlbmNlIGdyb3VwKiogYW5kIHRoZSBjb2VmZmljaWVudHMgaW5kaWNhdGUgdGhlIHNsb3BlIG9yIGRpZmZlcmVuY2UgaW4gbG9nIHJlbGF0aXZlIHBlcmNlbnQgY29uc3VtcHRpb24gcmF0ZXMgZm9yIGVhY2ggbGlzdGVkIGFnZSBncm91cCAqY29tcGFyZWQqIHRvIHRoaXMgcmVmZXJlbmNlIGdyb3VwLiAKCiMjIyMgQU5PVkEgYW5kIGxpbmVhciByZWdyZXNzaW9uIHdpdGggZml4ZWQgZWZmZWN0cwoKTm93IGxldCdzIGFjY291bnQgZm9yIHRoZSBwYWlyZWQgYGxvY2F0aW9uX25hbWVgIHN0cnVjdHVyZSB3aXRoaW4gb3VyIGRhdGEsIHNpbmNlIHRoZSBhYm92ZSBtb2RlbHMgdmlvbGF0ZSB0aGUgaW5kZXBlbmRlbmNlIGFzc3VtcHRpb25zIGZvciBBTk9WQSBhbmQgbGluZWFyIHJlZ3Jlc3Npb24uIFdlIGNhbiBkbyB0aGlzIGJ5IGFkZGluZyBhbm90aGVyIGZpeGVkIGVmZmVjdCB0byBib3RoIHRoZSBBTk9WQSBtb2RlbCBhbmQgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsLiAgRm9yIEFOT1ZBLCB0aGlzIG1lYW5zIHdlIGFyZSBub3cgZG9pbmcgYSB0d28td2F5IEFOT1ZBLCBzaW5jZSB3ZSBoYXZlIHR3byBpbmRlcGVuZGVudCB2YXJpYWJsZXMgKGFnZSBncm91cCBhbmQgY291bnRyeSkuICBGb3IgbGluZWFyIHJlZ3Jlc3Npb24sIHdlIGFyZSBub3cgYWRkaW5nIGEgZml4ZWQgZWZmZWN0IGZvciBjb3VudHJ5IHRvIG91ciBtb2RlbC4gIAoKIyMjIyB7LnNjcm9sbGFibGUgfQoKYGBge3J9CmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBhb3YobG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBhZ2VfZ3JvdXBfbmFtZSArIGxvY2F0aW9uX25hbWUsIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBsbShsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSB+IGFnZV9ncm91cF9uYW1lICsgbG9jYXRpb25fbmFtZSwgZGF0YSA9IC4pICU+JQogIHN1bW1hcnkoKQpgYGAKIyMjIyAKCkl0J3MgaGFyZCB0byBzZWUgdGhhdCB0aGVzZSByZXN1bHRzIG1hdGNoLCBzaW5jZSB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gb3V0cHV0IGRvZXNuJ3QgcHJpbnQgdGhlICRGJC1zdGF0aXN0aWMgZm9yIHRoZSBhZ2UgZ3JvdXBzIHRvZ2V0aGVyIG9yIHRoZSBjb3VudHJpZXMgdG9nZXRoZXI7IGl0IG9ubHkgZ2l2ZXMgcmVzdWx0cyBmb3IgaW5kaXZpZHVhbCAkdCQtdGVzdHMgb2YgZWFjaCByZWdyZXNzaW9uIGNvZWZmaWNpZW50LiAgV2UgY2FuIGdldCB0aGVzZSBncm91cGVkICRGJC1zdGF0aXN0aWNzIHVzaW5nIHRoZSBgYW5vdmEoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdGF0c2AgcGFja2FnZS4gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCBhY3R1YWxseSBkaXJlY3RseSBwZXJmb3JtIEFOT1ZBIGxpa2UgdGhlIGBhb3YoKWAgZnVuY3Rpb24sIGJ1dCBpbnN0ZWFkIHByaW50cyBhIHZhcmlhbmNlIHRhYmxlIHVzaW5nIGEgYGxtKClgIG9iamVjdC4KCmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG0obG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBhZ2VfZ3JvdXBfbmFtZSArIGxvY2F0aW9uX25hbWUsIGRhdGEgPSAuKSAlPiUKICBhbm92YSgpCgpgYGAKIyMjIyAKCldlIGNhbiBzZWUgdGhhdCBpbmRlZWQgdGhlICRGJC12YWx1ZXMgYW5kICRwJC12YWx1ZXMgZnJvbSBsaW5lYXIgcmVncmVzc2lvbiBtYXRjaCB0aG9zZSBmcm9tIEFOT1ZBLiBJbiB0aGlzIGNhc2UsIHRoaXMgYW5hbHlzaXMgc3VnZ2VzdHMgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFnZSBncm91cCBhbmQgY29uc3VtcHRpb24sIGV2ZW4gd2hlbiBjb250cm9sbGluZyBmb3IgY291bnRyeS4gIEl0IGFsc28gc3VnZ2VzdHMgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNvdW50cnkgYW5kIGNvbnN1bXB0aW9uLCBldmVuIHdoZW4gY29udHJvbGxpbmcgZm9yIGFnZSBncm91cC4gIEhvd2V2ZXIsIG9ubHkgdGhlIGZpcnN0IHJlbGF0aW9uc2hpcCBpcyBvdXIgcmVsYXRpb25zaGlwIG9mIGludGVyZXN0OyB0aGUgc2Vjb25kIGlzIG9ubHkgaW5jbHVkZWQgaW4gdGhlIG1vZGVsIHRvIGFjY291bnQgZm9yIHRoZSBkZXBlbmRlbnQgbmF0dXJlIG9mIHRoZSBkYXRhLgoKUmVtZW1iZXIsIHRoZSBBTk9WQSByZXN1bHRzIGluZGljYXRlIHRoYXQgdGhlIG1lYW5zIGFyZSBkaWZmZXJlbnQgYWNyb3NzIHRoZXNlIGdyb3VwcywgYnV0IGl0ICoqZG9lcyBub3QqKiBpbmZvcm0gdXMgYWJvdXQgd2hpY2ggZ3JvdXBzIGFyZSBkaWZmZXJlbnQuIEhvd2V2ZXIsIHRoZSBvcmlnaW5hbCBgbG0oKWAgb3V0cHV0IHVzaW5nIHRoZSBgc3VtbWFyeSgpfiBjb21tYW5kIGdpdmVzIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgc3BlY2lmaWMgZ3JvdXAgZGlmZmVyZW5jZXMuIFJlbWVtYmVyLCB0aG91Z2gsIHRoYXQgdGhlc2UgYXJlICoqcmVsYXRpdmUgdG8gdGhlIHJlZmVyZW5jZSoqIGxldmVsIGZvciB0aGUgYWdlIGdyb3VwIGFuZCBsb2NhdGlvbiBhbmQgdGhhdCB0aGVzZSB2YWx1ZXMgYXJlIGNhbGN1bGF0ZWQgZm9yIHRoZSBlZmZlY3Qgb24gY29uc3VtcHRpb24gd2hpbGUgY29udHJvbGxpbmcgZm9yIHRoZSBvdGhlciB2YXJpYWJsZSBpbiB0aGUgbW9kZWwuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG0obG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBhZ2VfZ3JvdXBfbmFtZSArIGxvY2F0aW9uX25hbWUsIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKYGBgCiMjIyMKCiMjIyMgQU5PVkEgYW5kIGxpbmVhciByZWdyZXNzaW9uIHdpdGggbWl4ZWQgZWZmZWN0cwoKV2UgY291bGQgaW5zdGVhZCBwZXJmb3JtIGEgc2ltaWxhciBhbmFseXNpcyBhcyB3ZSBkaWQgZm9yIHRoZSB0d28gZ3JvdXAgYW5hbHlzaXMgd2hlcmUgd2UgY29udHJvbGxlZCBmb3IgdGhlIHBhaXJlZCBkYXRhIHN0cnVjdHVyZSB1c2luZyBhIHJhbmRvbSBlZmZlY3QgYmFzZWQgb24gY291bnRyeSBJbiBwYXJ0aWN1bGFyLCB3ZSBjb3VsZCBpbmNsdWRlIGEgcmFuZG9tIGludGVyY2VwdCBmb3IgY291bnRyeS4gIFdlIGNvdWxkIGRvIHRoaXMgd2l0aGluIHRoZSBgYW92KClgIGZ1bmN0aW9uIHVzaW5nIGBFcnJvcigpYCBhbmQgd2l0aGluIHRoZSBgbG1lcigpYCBmdW5jdGlvbiB3aXRoIGAxIHwgdmFyaWFibGVfbmFtZWAuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgYW92KAogICAgbG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBhZ2VfZ3JvdXBfbmFtZSArIEVycm9yKGxvY2F0aW9uX25hbWUpLCAKICAgIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBsbWVyKAogICAgbG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBhZ2VfZ3JvdXBfbmFtZSArICgxIHwgbG9jYXRpb25fbmFtZSksIAogICAgZGF0YSA9IC4pICU+JQogIHN1bW1hcnkoKQpgYGAKCk5vdGljZSBub3cgdGhlIHJlc3VsdHMgb25seSBzaG93IGZvciB0aGUgYWdlIGdyb3VwIHZhcmlhYmxlLCBzaW5jZSB0aGlzIGlzIHRoZSBvbmx5IGZpeGVkIGVmZmVjdCBpbiB0aGUgbW9kZWwuICBIb3dldmVyLCBkZXBlbmRlbmNlIGluIHRoZSBkYXRhIGR1ZSB0byBjb3VudHJ5IGlzIHN0aWxsIGFjY291bnRlZCBmb3IgdGhyb3VnaCB0aGUgcmFuZG9tIGVmZmVjdC4KCklmIHdlIHVzZSBgYW5vdmEoKWAgaW5zdGVhZCBvZiBgc3VtbWFyeSgpYCBmb3Igb3VyIGBsbWVyKClgIG1vZGVsLCB3ZSBjYW4gc2VlIHRoZXkgZ2l2ZSB0aGUgc2FtZSByZXN1bHRzLgpgYGB7cn0KYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGFvdigKICAgIGxvZzEwKFJlbGF0aXZlX1BlcmNlbnQpIH4gYWdlX2dyb3VwX25hbWUgKyBFcnJvcihsb2NhdGlvbl9uYW1lKSwgCiAgICBkYXRhID0gLikgJT4lCiAgc3VtbWFyeSgpCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgbG1lcigKICAgIGxvZzEwKFJlbGF0aXZlX1BlcmNlbnQpIH4gYWdlX2dyb3VwX25hbWUgKyAoMSB8IGxvY2F0aW9uX25hbWUpLCAKICAgIGRhdGEgPSAuKSAlPiUKICBhbm92YSgpCmBgYAoKCiMjIyBNb2RlbGluZyBhbGwgZ3JvdXBzIG9mIGludGVyZXN0CgpOb3cgd2UgY2FuIGV4dGVuZCBvdXQgbW9kZWwgdG8gaW5jbHVkZSBpbmNsdWRlIGBzZXhgLCBgYWdlX2dyb3VwX25hbWVgIGFuZCBgbG9jYXRpb25fbmFtZWAgYWxsIGluIHRoZSBzYW1lIGxpbmVhciBtb2RlbCBhbmQgZ2V0IGluZm9ybWF0aW9uIGFib3V0IGhvdyBlYWNoIG9mIHRoZXNlIGZhY3RvcnMgaW5mbHVlbmNlcyBkaWV0YXJ5IGNvbnN1bXB0aW9uLCB3aGlsZSBhY2NvdW50aW5nIGZvciB0aGUgb3RoZXIgZmFjdG9ycy4gU2luY2Ugd2UgYXJlIHByaW1hcmlseSBpbnRlcmVzdGVkIGluIHRoZSBlZmZlY3RzIG9mIHNleCBhbmQgYWdlLCBidXQgd2FudCB0byBhY2NvdW50IGZvciB0aGUgZGVwZW5kZW5jZSBpbiB0aGUgZGF0YSBkdWUgdG8gcmVwZWF0ZWQgbWVhc3VyZW1lbnRzIGJ5IGNvdW50cnksIHdlIHdpbGwgaW5jbHVkZSBgc2V4YCBhbmQgYGFnZV9ncm91cF9uYW1lYCBhcyBmaXhlZCBlZmZlY3RzIGFuZCBpbmNvcnBvcmF0ZSBhIHJhbmRvbSBpbnRlcmNlcHQgZm9yIGBsb2NhdGlvbl9uYW1lYC4gIAoKYGBge3J9CmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBsbWVyKAogICAgbG9nMTAoUmVsYXRpdmVfUGVyY2VudCkgfiBzZXggK2FnZV9ncm91cF9uYW1lICsgKDEgfCBsb2NhdGlvbl9uYW1lKSwgCiAgICBkYXRhID0gLikgJT4lCiAgYW5vdmEoKQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGxtZXIoCiAgICBsb2cxMChSZWxhdGl2ZV9QZXJjZW50KSB+IHNleCArYWdlX2dyb3VwX25hbWUgKyAoMSB8IGxvY2F0aW9uX25hbWUpLCAKICAgIGRhdGEgPSAuKSAlPiUKICBzdW1tYXJ5KCkKYGBgCgpMb29raW5nIGF0IHRoZSBgYW5vdmEoKWAgb3V0cHV0LCB3ZSBjYW4gc2VlIHRoYXQgc2V4IGFuZCBhZ2UgZ3JvdXAgYm90aCBoYXZlIHNpZ25pZmljYW50IGFzc29jaWF0aW9ucyB3aXRoIHRoZSBjb25zdW1wdGlvbiBvZiByZWQgbWVhdCwgd2hlbiBjb250cm9sbGluZyBmb3IgdGhlIG90aGVyIHZhcmlhYmxlLiAgQWRkaXRpb25hbGx5LCBieSBsb29raW5nIGF0IHRoZSBpbmRpdmlkdWFsIGNvZWZmaWNpZW50IGVzdGltYXRlcyBpbiB0aGUgYHN1bW1hcnkoKWAgb3V0cHV0LCB3ZSBzZWUgdGhhdCBtYWxlcyB0ZW5kIHRvIGhhdmUgaGlnaGVyIHJlZCBtZWF0IGNvbnN1bXB0aW9uIGNvbXBhcmVkIHRvIGZlbWFsZXMgKHBvc2l0aXZlIGNvZWZmaWNpZW50IGZvciBgc2V4TWFsZWApIGFuZCB0aGF0IGNvbnN1bXB0aW9uIHNlZW1zIHRvIGRlY3JlYXNlIHdpdGggaW5jcmVhc2luZyBhZ2UgKG5lZ2F0aXZlIGNvZWZmaWNpZW50cyBmb3IgYWxsIHRoZSBhZ2UgZ3JvdXAgY2F0ZWdvcmllcyB0aGF0IGFwcGVhciB0byBiZWNvbWUgbGFyZ2VyIGluIG1hZ25pdHVkZSB3aXRoIGluY3JlYXNpbmcgYWdlKS4KCiMjICoqRGF0YSBWaXN1YWxpemF0aW9uKioKKioqCgpgYGB7ciwgZWNobyA9IEZBTFNFfQojIEZvciBpbnN0cnVjdG9ycyB3aG8gd2lzaCB0byBzdGFydCBhdCB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgbG9hZCB0aGUgZGF0YQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkKYGBgCgpOb3cgdGhhdCB3ZSBoYXZlIHN0YXRpc3RpY2FsbHkgYW5hbHl6ZWQgdGhlIGNvbnN1bXB0aW9uIG9mIHJlZCBtZWF0IGJhc2VkIG9uIHRoZSBsb2NhdGlvbiwgc2V4LCBhbmQgYWdlIGdyb3VwIG9mIGRpZmZlcmVudCBwb3B1bGF0aW9ucyBhcm91bmQgdGhlIHdvcmxkLiBMZXQncyBtYWtlIHNvbWUgdmlzdWFsaXphdGlvbnMgdG8gaGVscCB3aXRoIG91ciBpbnRlcnByZXRhdGlvbnMuCgojIyMgUmVkIE1lYXQKCkxldCdzIHRyeSB0byBtYWtlIGEgcGxvdCB0aGF0IHNob3dzIHRoZSByZWxhdGlvbnNoaXAgb2YgYWdlIGdyb3VwLCBzZXgsIGFuZCBsb2NhdGlvbiBvbiBjb25zdW1wdGlvbiBvZiByZWQgbWVhdC4KCkZpcnN0IHdlIHdpbGwgZmlsdGVyIG91ciBkYXRhIGZvciBvbmx5IHRoZSBkYXRhIGFzc29jaWF0ZWQgd2l0aCByZWQgbWVhdCwgYW5kIHRoZW4gd2Ugd2lsbCBjcmVhdGUgYSBib3ggcGxvdCBncmFwaCB3aXRoIGFnZSBncm91cCBhcyB0aGUgeCBheGlzLCBidXQgaW5jbHVkZSBib3ggcGxvdHMgZm9yIGVhY2ggc2V4IGZvciBlYWNoIGFnZSBncm91cC4gV2UgY2FuIGluY2x1ZGUgYW4gYWRkaXRpb25hbCBzdWJwbG90IHRvIGp1c3QgbG9vayBhdCB0aGUgcmVsYXRpb25zaGlwIG9mIHNleCBhbmQgY29uc3VtcHRpb24uIFJlY2FsbCB0aGF0IHRoZSBgZ2dwbG90MmAgcGFja2FnZSBpcyB2ZXJ5IHVzZWZ1bCBmb3IgbWFraW5nIGZpZ3VyZXMgYW5kIHVzZXMgYSBsYXllcmluZyBzdHJ1Y3R1cmUgdG8gbWFrZSBwbG90cyB1c2luZyB0aGUgYCtgIGJldHdlZW4gbGF5ZXJzLgoKYGBge3J9CgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYWdlX2dyb3VwX25hbWUsCiAgICAgICAgICAgICB5ID0gUmVsYXRpdmVfUGVyY2VudCwgCiAgICAgICAgICAgY29sID0gc2V4KSkgKwogIGdlb21fYm94cGxvdCgpICsKIyB0aGlzIGFkZHMgdGhlIGluZGl2aWR1YWwgcG9pbnRzIGZvciB0aGUgc2V4IGNvbXBhcmlzb24KICBnZW9tX2ppdHRlcihhZXMoeCA9IHNleCwgCiAgICAgICAgICAgICAgICAgIHkgPSBSZWxhdGl2ZV9QZXJjZW50KSwgCiMgd2lkdGggc3BlY2lmaWVzIGhvdyB3aWRlIHRoZSBwb2ludHMgd2lsbCBiZSBwbG90dGVkCiAgICAgICAgICAgICAgd2lkdGggPSAuMiwgCiAgICAgICAgICAgICAgIHNpemUgPSAyLCAKICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArCiMgdGhpcyBhbmdsZXMgdGhlIHggYXhpcyB0ZXh0IGFuZCByZW1vdmVzIHRoZSBsZWdlbmQKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDcwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCk9LLCB0aGlzIGlzIHByZXR0eSBnb29kLCBidXQgd2UgY2FuIGRvIGJldHRlci4KCkxldCdzIHRyeSBzcGVjaWZpY2FsbHkgbG9va2luZyBhdCB0aGUgY291bnRyaWVzIHRoYXQgb3Zlci1jb25zdW1lZCByZWQgbWVhdC4gV2UgY2FuIGxvb2sgYXQgdGhlc2UgY291bnRyaWVzIGJ5IGZpbHRlcmluZyBvdXIgZGF0YSB3aGVyZSBgUmVsYXRpdmVfUGVyY2VudGAgd2FzIGdyZWF0ZXIgdGhhbiAxMDAlLiBOb3cgd2Ugd2lsbCBvdmVybGFwIHRoZSBqaXR0ZXIgcG9pbnRzIGFuZCB0aGUgYm94IHBsb3QgdXNpbmcgdGhlIGBwb3NpdGlvbl9qaXR0ZXJkb2dlKClgIGFzIHRoZSBwb3NpdGlvbiBpbiBgZ2VvbV9wb250KClgLiBJbiBvcmRlciB0byBub3Qgb2JzY3VyZSBvdXIgYm94IHBsb3RzLCB3ZSBjYW4gdXNlIHRoZSBhcmd1bWVudCBgYWxwaGFgIHRvIG1ha2Ugb3VyIGppdHRlciBwb2ludHMgbW9yZSB0cmFuc3BhcmVudC4KCmBgYHtyfQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGZpbHRlcihSZWxhdGl2ZV9QZXJjZW50ID4gMTAwKSAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBSZWxhdGl2ZV9QZXJjZW50LAogICAgICAgICAgICAgeCA9IGFnZV9ncm91cF9uYW1lLCAKICAgICAgICAgIGZpbGwgPSBzZXgpKSArCiMgdGhpcyBwb3NpdGlvbiBvcHRpb24gd2lsbCBzZXBhcmF0ZSB0aGUgcG9pbnRzIGJ5IHNleCAKIyB0aGlzIGlzIGRldGVybWluZWQgYnkgdGhlIGZpbGwgYXJndW1lbnQgaW4gdGhlIGdncGxvdCgpIGZ1bmN0aW9uCiMgY291bGQgYWxzbyB1c2UgY29sIGFyZ3VtZW50IGJ1dCBpdCB3b3VsZCBjaGFuZ2UgdGhlIHN0eWxlIGEgYml0CiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKCksCiAgICAgICAgICAgICAgYWVzKGNvbCA9IHNleCksCiAgICAgICAgICAgICAgICBhbHBoYSA9IDMvMTApICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNzAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkpCmBgYAoKV2hhdCBhcmUgdGhlIGNvdW50cmllcyB0aGF0IGhhdmUgc3VjaCBoaWdoIGNvbnN1bXB0aW9uIHJhdGVzPwoKYGBge3J9CmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBmaWx0ZXIoUmVsYXRpdmVfUGVyY2VudCA+IDEwMDApCmBgYAogCiBMb29rcyBsaWtlIHRoZSBtYWxlcyBpbiBMYW9zIGFuZCBUaW1vcl9MZXN0ZSBoYXZlIHRoZSBoaWdoZXN0IGNvbnN1bXB0aW9uLgoKIApOb3cgbGV0J3MgcGxvdCBqdXN0IHRoZSBwb3B1bGF0aW9ucyB0aGF0IGVhdCBsZXNzIHRoYW4gdGhlIG9wdGltYWwgYW1vdW50IGJ5IGZpbHRlcmluZyBmb3IgYFJlbGF0aXZlX1BlcmNlbnRgIDwgMTAwJS4KIApgYGB7cn0KCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBmaWx0ZXIoUmVsYXRpdmVfUGVyY2VudCA8IDEwMCkgJT4lCiAgZ2dwbG90KGFlcyh5ID0gUmVsYXRpdmVfUGVyY2VudCwgCiAgICAgICAgICAgICB4ID0gYWdlX2dyb3VwX25hbWUsIAogICAgICAgICAgZmlsbCA9IHNleCkpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoKSwgCiAgICAgICAgICAgICAgYWVzKGNvbCA9IHNleCksIAogICAgICAgICAgICAgICAgYWxwaGEgPSAzLzEwKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDcwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQpgYGAKCk5pY2UhIEl0IHdvdWxkIGJlIG5pY2UgdG8gYmUgYWJsZSB0byBrbm93IHdoYXQgY291bnRyaWVzIGVhY2ggZGF0YSBwb2ludCBjb3JyZXNwb25kcyB0by4gT25lIHdheSB0byBkbyB0aGlzIGlzIHVzaW5nIGEgcGFja2FnZSBjYWxsZWQgYGdnaXJhcGhgLiBUaGlzIHBhY2thZ2UgaXMgcmVhbGx5IGhlbHBmdWwgZm9yIGNyZWF0aW5nIGludGVyYWN0aXZlIGdyYXBocy4gCgpXZSB3aWxsIHVzZSB0aGUgYGdlb21fcG9pbnRfaW50ZXJhY3RpdmUoKWAgZnVuY3Rpb24gdG8gYWxsb3cgdXMgdG8gaG92ZXIgb3ZlciBwb2ludHMgdG8gZGlzcGxheSB0aGUgY291bnRyeSBuYW1lLiBXZSBpbmRpY2F0ZSB3aGF0IGxhYmVsIHdlIHdhbnQgd2l0aCB0aGUgYHRvb2x0aXBgIGFyZ3VtZW50LgpUaGlzIGZ1bmN0aW9uIGlzIHNpbWlsYXIgdG8gdGhlIG5vcm1hbCBgZ2VvbV9wb2ludCgpYCBmdW5jdGlvbi4gVGh1cywgd2Ugd2lsbCBpbmNsdWRlIHRoZSBzYW1lIGFyZ3VtZW50cyBhcyBiZWZvcmUuIEhvd2V2ZXIsIHdlIHdpbGwgYWxzbyBzcGxpdCB0aGUgbWFsZSBhbmQgZmVtYWxlIGRhdGEgdXNpbmcgYGZhY2V0X3dyYXAoKWAgdG8gbWFrZSB0aGluZ3MgYSBiaXQgbGVzcyBvdmVyd2hlbG1pbmcuCgpOb3RpY2UgdGhhdCB3ZSBhcmUgY3JlYXRpbmcgYSBwbG90IG9iamVjdCBiZWZvcmUgd2UgdXNlIHRoZSBgZ2VvbV9wb2ludF9pbnRlcmFjdGl2ZSgpYC4KCldlIGFyZSBhbHNvIHJlbmRlcmluZyB0aGUgcGxvdCB3aXRoIHRoZSBgZ2lyYWZlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dpcmFwaGAgcGFja2FnZS4KCgpgYGB7ciwgZXZhbCA9IFRSVUV9CgpnIDwtIGFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZm9vZCA9PSAicmVkIG1lYXQiKSAlPiUKICBmaWx0ZXIoUmVsYXRpdmVfUGVyY2VudCA8IDEwMCkgJT4lCiAgZ2dwbG90KGFlcyh5ID0gUmVsYXRpdmVfUGVyY2VudCAsIAogICAgICAgICAgICAgeCA9IGFnZV9ncm91cF9uYW1lLCAKICAgICAgICAgIGZpbGwgPSBzZXgpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGZhY2V0X3dyYXAofnNleCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNzAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkpCiAgCiBnIDwtIGcgKyBnZW9tX3BvaW50X2ludGVyYWN0aXZlKGFlcygKICAgICAgICAgICAgICAgIGNvbG9yID0gc2V4LCAKICAgICAgICAgICAgICB0b29sdGlwID0gbG9jYXRpb25fbmFtZSksIAogICAgICAgICAgICAgICAgIHNpemUgPSAyLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZSgpLCAKICAgICAgICAgICAgICAgIGFscGhhID0gMy8xMCkgCiAKZ2lyYWZlKGNvZGUgPSBwcmludChnKSkKCmBgYAoKCkNvb2whIAoKRnJvbSB0aGlzIHBsb3Qgd2UgY2FuIHNlZSB0aGUgY291bnRyaWVzIHdpdGggcG9wdWxhdGlvbnMgdGhhdCBkbyB3ZWxsIGJ5IG5vdCBvdmVyLWNvbnN1bWluZyByZWQgbWVhdCwgKGFzIG92ZXItY29uc3VtcHRpb24gaXMgYXNzb2NpYXRlZCB3aXRoIGhlYWx0aCByaXNrKS4gV2Ugc2VlIHRoYXQgZGlmZmVyZW50IGNvdW50cmllcyBncmVhdGx5IHZhcnksIHdlIGNhbiBzZWUgdGhhdCBvdmVyYWxsIHlvdW5nZXIgcG9wdWxhdGlvbnMgYXBwZWFyIHRvIGNvbnN1bWUgbW9yZSByZWQgbWVhdCwgYW5kIG1lbiBhcHBlYXIgdG8gY29uc3VtZSByZWQgbWVhdC4KCkxldCdzIGRvIHRoZSBzYW1lIHRoaW5nIGZvciB0aGUgb3Zlci1jb25zdW1pbmcgY291bnRyaWVzLiBXZSBjYW4gYWxzbyB0YWtlIHRoaXMgb25lIHN0ZXAgZnVydGhlciB0byBzaG93IGFsbCB0aGUgcG9pbnRzIGZvciB0aGUgc2FtZSBjb3VudHJ5IHdoZW4gd2UgaG92ZXIgb3ZlciBvbmUgZGF0YSBwb2ludCBieSB1c2luZyB0aGUgYGRhdGFfaWRgIGFyZ3VtZW50IG9mIHRoZSBgZ2VvbV9wb2ludF9pbnRlcmFjdGl2ZSgpYCBmdW5jdGlvbi4gCgoKV2UgY2FuIGFsc28gYWRkIGxpbmtzIHRvIFdpa2lwZWRpYSBwYWdlcyBmb3IgdGhlc2UgY291bnRyaWVzIHVzaW5nIHRoZSBgb25jbGlja2AgYXJndW1lbnQuIFNlZSB0aGlzIFtsaW5rXShodHRwczovL2RhdmlkZ29oZWwuZ2l0aHViLmlvL2dnaXJhcGgvYXJ0aWNsZXMvb2ZmY3Jhbi91c2luZ19nZ2lyYXBoLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdXNpbmcgdGhlIGBnZ2lycGFoYCBwYWNrYWdlLiBXZSB3aWxsIHVzZSB0aGUgYmFzZSBgc3ByaW50ZigpYCBmdW5jdGlvbiB0byBmb3JtYXQgb3VyIHVybHMgZm9yIHRoZSBXaWtpcGVkaWEgbGlua3MgaW50byBDIHN0eWxlIHRvIG9wZW4gYSBuZXcgdGFiIGZvciB0aGUgbGluayB3aGVuIGEgdXNlciBjbGlja3Mgb24gdGhlIGZpZ3VyZS4KCmBgYHtyLCBldmFsID0gVFJVRX0KCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPD4lIAogIG11dGF0ZShsaW5rID0gc3ByaW50Zigid2luZG93Lm9wZW4oXCIlcyVzXCIpIiwKICAiaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS8iLCAgCiAgYXMuY2hhcmFjdGVyKHB1bGwoYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbl9uYW1lKSkpKQoKZyA8LSBhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgZmlsdGVyKFJlbGF0aXZlX1BlcmNlbnQgPiAxMDApICU+JQogIGdncGxvdChhZXMoeSA9IFJlbGF0aXZlX1BlcmNlbnQgLCAKICAgICAgICAgICAgIHggPSBhZ2VfZ3JvdXBfbmFtZSwgCiAgICAgICAgICAgICBmaWxsID0gc2V4KSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZmFjZXRfd3JhcCh+c2V4KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDcwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkgKwogIGV4cGFuZF9saW1pdHMoeSA9IDk5KQoKICAKIGcgPC0gZyArIGdlb21fcG9pbnRfaW50ZXJhY3RpdmUoYWVzKAogICAgICAgICAgICAgICAgY29sb3IgPSBzZXgsIAogICAgICAgICAgICAgIHRvb2x0aXAgPSBsb2NhdGlvbl9uYW1lLAogICAgICAgICAgICAgIGRhdGFfaWQgPSBsb2NhdGlvbl9uYW1lLAogICAgICAgICAgICAgIG9uY2xpY2sgPSBsaW5rKSwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDIsCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKCksIAogICAgICAgICAgICAgICAgYWxwaGEgPSAzLzEwKSAKIApnIDwtIGcgKyBnZW9tX3BvaW50X2ludGVyYWN0aXZlKGRhdGEgPQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgZmlsdGVyKFJlbGF0aXZlX1BlcmNlbnQgPiAxMDApICU+JQogIGZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIiksCiAgIGFlcyhmaWxsID0gbG9jYXRpb25fbmFtZSwgCiAgICB0b29sdGlwID0gbG9jYXRpb25fbmFtZSwKICAgIGRhdGFfaWQgPSBsb2NhdGlvbl9uYW1lLAogICAgb25jbGljayA9IGxpbmspLAogICAgICAgc2l6ZSA9IDQsCiAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoKSwKICAgICAgYWxwaGEgPSA1LzEwLCAKICAgICAgY29sb3IgPSAiYmxhY2siKQogCmdpcmFmZShjb2RlID0gcHJpbnQoZykpCgpgYGAKCiMjIyBVbml0ZWQgU2F0ZXMgRGF0YQoKTm93IGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBVUyBkYXRhIHNwZWNpZmljYWxseS4KCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKIGZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIikgJT4lCiAgY291bnQob3B0X2FjaGlldmVkKQpgYGAKCk9LLCBpdCBsb29rcyBsaWtlIG9wdGltYWwgY29uc3VtcHRpb24gbGV2ZWxzIHdlcmUgYWNoaWV2ZWQgZm9yIG9ubHkgMTAlIG9mIHRoZSBkaWV0YXJ5IGZhY3RvcnMuCgpMZXQncyBsb29rIGF0IG1hbGVzIGFuZCBmZW1hbGVzIHNlcGFyYXRlbHk6CgojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKQ2FuIHlvdSBjb21lIHVwIHdpdGggdGhlIGNvZGUgZm9yIGhvdyB5b3Ugd291bGQgZG8gdGhpcz8KCiMjIyMKCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogICAgZmlsdGVyKHNleCA9PSAiRmVtYWxlIiwgCiBsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIikgJT4lCmNvdW50KG9wdF9hY2hpZXZlZCwgZm9vZCkKCmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgICBmaWx0ZXIoc2V4ID09ICJNYWxlIiwgCiBsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIikgJT4lCmNvdW50KG9wdF9hY2hpZXZlZCwgZm9vZCkKCmBgYAo8L2RldGFpbHM+CioqKgoKYGBge3IsIGVjaG8gPSBGQUxTRX0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICAgIGZpbHRlcihzZXggPT0gIkZlbWFsZSIsIAogbG9jYXRpb25fbmFtZSA9PSAiVW5pdGVkIFN0YXRlcyIpICU+JQpjb3VudChvcHRfYWNoaWV2ZWQsIGZvb2QpCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogICAgZmlsdGVyKHNleCA9PSAiTWFsZSIsIAogbG9jYXRpb25fbmFtZSA9PSAiVW5pdGVkIFN0YXRlcyIpICU+JQpjb3VudChvcHRfYWNoaWV2ZWQsIGZvb2QpCmBgYAoKClNvIGZlbWFsZXMgYXJlIGEgYml0IGJldHRlciBhYm91dCBub3Qgb3Zlci1jb25zdW1pbmcgc29kaXVtIGluIHRoZSBVbml0ZWQgU3RhdGVzIHJlbGF0aXZlIHRvIG1hbGVzLiAgQm90aCBncm91cHMgYXJlIGRvaW5nIHdlbGwgd2l0aCBhdm9pZGluZyB0cmFucyBmYXR0eSBhY2lkcy4gTGV0J3MgbG9vayBtb3JlIGNsb3NlbHkgYXQgd2hpY2ggZGlldGFyeSBjb21wb25lbnRzIGhhdmUgaGlnaCBhbmQgbG93IGNvbnN1bXB0aW9uIGluIHRoZSBVbml0ZWQgU3RhdGVzOgoKYGBge3J9CgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCmZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIikgJT4lCmdncGxvdChhZXMoeSA9IFJlbGF0aXZlX1BlcmNlbnQgLCAKICAgICAgICAgICB4ID0gZm9vZCwgCiAgICAgICAgZmlsbCA9IHNleCkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDcwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKSArCiAgZmFjZXRfd3JhcCh+ZGlyZWN0aW9uLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKCksIAogICAgICAgICAgICAgICAgYWxwaGEgPSAzLzEwKQoKYGBgCgpPSywgc28gd2UgY2FuICBpbmRlZWQgc2VlIHRoYXQgb3ZlcmFsbCBjb25zdW1wdGlvbiBvZiBzb2RpdW0gYW5kIHRyYW5zIGZhdHR5IGFjaWRzIGlzIHByZXR0eSBjbG9zZSB0byBvcHRpbWFsLiBTbyB0aGF0J3MgZ3JlYXQuIEhvd2V2ZXIsIEJvdGggbWFsZXMgYW5kIGZlbWFsZXMgYXJlIG92ZXItY29uc3VtaW5nIHByb2Nlc3NlZCBtZWF0LCByZWQgbWVhdCwgYW5kIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMuIE9uIHRoZSBvdGhlciBoYW5kIGJvdGggZ2VuZGVycyBhcmUgbm90IGdldHRpbmcgYWRlcXVhdGUgaW50YWtlIG9mIGFsbCB0aGUgb3RoZXIgZGlldGFyeSBmYWN0b3JzIGZvciBvcHRpbWFsIGhlYWx0aC4gVGhlIHBvcHVsYXRpb24gaW4gdGhlIFVuaXRlZCBzdGF0ZXMgaGFzIGVzcGVjaWFsbHkgcG9vciBpbnRha2Ugb2YgcG9seXVuc2F0dXJhdGVkIGZhdHMuIGl0IGFsc28gbG9va3MgbGlrZSBpbiBtb3N0IGNhc2VzIGZlbWFsZXMgYXJlIGdldHRpbmcgbGVzcyBvZiB0aGUgZGlldGFyeSBmYWN0b3JzIHRoYXQgcG9zZSBoZWFsdGggcmlza3Mgd2hlbiB1bmRlci1jb25zdW1lZCwgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIGZydWl0cy4KCgpIb3cgYWJvdXQgaWYgd2UgbG9vayBhdCBhZ2UgZ3JvdXBzLiBGaXJzdCBsZXQncyBsb29rIGF0IHRoZSBkaWV0YXJ5IGNvbXBvbmVudHMgd2l0aCB0aGF0IHdlcmUgb3Zlci1jb25zdW1lZCBpbiB0aGUgVW5pdGVkIFN0YXRlcy4KCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpDYW4geW91IGNvbWUgdXAgd2l0aCB0aGUgY29kZSBmb3IgdGhpcyBvbiB5b3VyIG93bj8KCiMjIyMKCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+CgpgYGB7cn0KCnBsb3RfYWdlX2dyb3VwcyA8LWFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIlVuaXRlZCBTdGF0ZXMiLCAKICAgICAgICAgICBkaXJlY3Rpb24gPT0gImhpZ2giKSAlPiUKZ2dwbG90KGFlcyh5ID0gUmVsYXRpdmVfUGVyY2VudCwgCiAgICAgICAgICAgeCA9IGZvb2QsIAogICAgICAgIGZpbGwgPSBhZ2VfZ3JvdXBfbmFtZSkpICsKICBmYWNldF93cmFwKH5mb29kLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKCksIAogICAgICAgICAgICAgICAgYWxwaGEgPSAzLzEwKQoKCmBgYAo8L2RldGFpbHM+CgoqKioKCmBgYHtyfQpwbG90X2FnZV9ncm91cHMgCmBgYAoKT0shIEl0IGxvb2tzIGxpa2UgYWdlIHJlYWxseSBpbmZsdWVuY2VzIHRoZSBjb25zdW1wdGlvbiBvZiB0aGVzZSBkaWV0YXJ5IGZhY3RvcnMuIFdpdGggdGhlIGV4Y2VwdGlvbiBvZiB0cmFucyBmYXR0eSBhY2lkcywgdGhlIGNvbnN1bXB0aW9uIG9mIGFsbCBvZiB0aGVzZSBkaWV0YXJ5IGZhY3RvcnMgc2VlbXMgdG8gZGVjcmVhc2Ugd2l0aCBhZ2UuICBMZXQncyBhbHNvIHVzZSB0aGVgc2NhbGVfZmlsbF92aXJpZGlzKClgIGZ1bmN0aW9uIG9mIHRoZSBgdmlyaWRpc2AgcGFja2FnZSB0byBjaGFuZ2UgdGhlIGNvbG9ycyBvZiBvdXIgcGxvdC4gVGhpcyBwYWNrYWdlIHVzZXMgcGFsZXR0ZXMgb2YgY29sb3JzIHRoYXQgYXJlIGRpc2Nlcm5pYmxlIGZvciBpbmRpdmlkdWFscyB3aG8gYXJlIGNvbG9yYmxpbmQuIAoKYGBge3J9CgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCmZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIiwgCiAgICAgICAgICAgZGlyZWN0aW9uID09ICJoaWdoIikgJT4lCmdncGxvdChhZXMoeSA9IFJlbGF0aXZlX1BlcmNlbnQsIAogICAgICAgICAgIHggPSBmb29kLCAKICAgICAgICBmaWxsID0gYWdlX2dyb3VwX25hbWUpKSArCiAgZmFjZXRfd3JhcCh+Zm9vZCwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZSgpLCAKICAgICAgICAgICAgICAgIGFscGhhID0gMy8xMCkrCiNjaGFuZ2UgdGhlIGNvbG9ycyBmcm9tIHJhaW5ib3cgdG8gcHVycGxlL2dyZWVuL3llbGxvdwogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICB0aGVtZV9saW5lZHJhdygpICsgCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID03LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKTmljZSEKCgpOb3cgbGV0J3MgbG9vayBhdCB0aGUgZGlldGFyeSBmYWN0b3JzIHRoYXQgd2hlbiBjb25zdW1lZCBhdCBsb3cgbGV2ZWxzIGluY3JlYXNlIGhlYWx0aCByaXNrOgoKCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpBZ2Fpbiwgc2VlIGlmIHlvdSBjb21lIHVwIHdpdGggdGhlIGNvZGUgZm9yIHRoaXMgb24geW91ciBvd24/CgojIyMjCgoqKioKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHJldmVhbCB0aGUgY29kZS4gPC9zdW1tYXJ5PgoKYGBge3J9Cmxvd19mb29kc19wbG90IDwtYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQpmaWx0ZXIobG9jYXRpb25fbmFtZSA9PSAiVW5pdGVkIFN0YXRlcyIsIAogICAgICAgICAgIGRpcmVjdGlvbiA9PSAibG93IikgJT4lCmdncGxvdChhZXMoeSA9IFJlbGF0aXZlX1BlcmNlbnQsIAogICAgICAgICAgIHggPSBmb29kLCAKICAgICAgICBmaWxsID0gYWdlX2dyb3VwX25hbWUpKSArCiAgZmFjZXRfd3JhcCh+Zm9vZCwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZSgpLCAKICAgICAgICAgICAgICAgIGFscGhhID0gMy8xMCkrCiNjaGFuZ2UgdGhlIGNvbG9ycyBmcm9tIHJhaW5ib3cgdG8gcHVycGxlL2dyZWVuL3llbGxvdwogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICB0aGVtZV9saW5lZHJhdygpICsgCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID03LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKPC9kZXRhaWxzPiAKKioqCgoKYGBge3J9Cmxvd19mb29kc19wbG90CmBgYAoKCgpJbnRlcmVzdGluZywgd2Ugc2VlIHRoYXQgZm9yIHRoZSBmb29kcyB0aGF0IGFyZSBvdmVyIGNvbnN1bWVkIChwcm9jZXNzZWQgbWVhdCwgcmVkIG1lYXQsIHNvZGl1bSwgYW5kIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMpLCBjb25zdW1wdGlvbiBhcHBlYXJzIHRvIGRlY3JlYXNlIHdpdGggYWdlLiBGb3IgdGhlIGZvb2RzIHRoYXQgYXJlIHVuZGVyIGNvbnN1bWVkLCBtYW55IGFwcGVhciB0byByaXNlIGFuZCBmYWxsIHdpdGggYWdlLgoKIyMjIE92ZXJhbGwgdHJlbmRzCgpGaW5hbGx5LCB3ZSB3b3VsZCBsaWtlIHRvIGdldCBhIGdlbmVyYWwgc2Vuc2Ugb2YgaG93IGNvbnN1bXB0aW9uIG9mIHRoZXNlIGRpZXRhcnkgZmFjdG9ycyBkaWZmZXJzIGFyb3VuZCB0aGUgd29ybGQgYW5kIHdlIHdvdWxkIGxpa2UgdG8ga25vdyBob3cgdGhlIFVTIGNvbXBhcmVzIHRvIG90aGVyIGNvdW50cmllcy4gCgpCZWZvcmUgd2UgZG8gdGhpcyBsZXQncyBjaGFuZ2UgdGhlIGxhYmVscyBvZiB0aGUgZm9vZHMgYnkgYWRkaW5nIG5ldyBsaW5lIGJyZWFrcyAoYCJcbiJgKSBzbyB0aGF0IHRoZXkgd2lsbCBmaXQgbW9yZSBlYXNpbHkgb24gb3VyIGdyYXBocy4KCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpTZWUgaWYgeW91IGNvbWUgdXAgd2l0aCB0aGUgY29kZSBmb3IgdGhpcyBvbiB5b3VyIG93bj8KCiMjIyMKCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlIGZvciB0aGUgYGRpZXRfYW5kX2d1aWRlbGluZXNgIGFuZCB0aGUgYGFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lc2AgZGF0YS4gPC9zdW1tYXJ5PgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXNbWyJmb29kIl1dIDwtIHN0cl9yZXBsYWNlX2FsbCgKICBkaWV0X2FuZF9ndWlkZWxpbmVzW1siZm9vZCJdXSwgCiAgInN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMiLCAKICAic3VnYXItc3dlZXRlbmVkXG5iZXZlcmFnZXMiKQpkaWV0X2FuZF9ndWlkZWxpbmVzW1siZm9vZCJdXSA8LSBzdHJfcmVwbGFjZV9hbGwoCiAgZGlldF9hbmRfZ3VpZGVsaW5lc1tbImZvb2QiXV0sCiAgInNlYWZvb2Qgb21lZ2EtMyBmYXR0eSBhY2lkcyIsIAogICJzZWFmb29kIG9tZWdhLTNcbmZhdHR5IGFjaWRzIikKZGlldF9hbmRfZ3VpZGVsaW5lc1tbImZvb2QiXV0gPC0gc3RyX3JlcGxhY2VfYWxsKAogIGRpZXRfYW5kX2d1aWRlbGluZXNbWyJmb29kIl1dLCAKICAicG9seXVuc2F0dXJhdGVkIGZhdHR5IGFjaWRzIiwgCiAgInBvbHl1bnNhdHVyYXRlZFxuZmF0dHkgYWNpZHMiKQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzW1siZm9vZCJdXSA8LSBzdHJfcmVwbGFjZV9hbGwoCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lc1tbImZvb2QiXV0sIAoic3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyIsIAoic3VnYXItc3dlZXRlbmVkXG5iZXZlcmFnZXMiKQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzW1siZm9vZCJdXSA8LSBzdHJfcmVwbGFjZV9hbGwoCiAgYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzW1siZm9vZCJdXSwgCiAgInNlYWZvb2Qgb21lZ2EtMyBmYXR0eSBhY2lkcyIsIAogICJzZWFmb29kIG9tZWdhLTNcbmZhdHR5IGFjaWRzIikKCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lc1tbImZvb2QiXV0gPC0gc3RyX3JlcGxhY2VfYWxsKAogIGFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lc1tbImZvb2QiXV0sIAogICJwb2x5dW5zYXR1cmF0ZWQgZmF0dHkgYWNpZHMiLCAKICAicG9seXVuc2F0dXJhdGVkXG5mYXR0eSBhY2lkcyIpCgpgYGAKCjwvZGV0YWlscz4KKioqCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBzZWxlY3QoZm9vZCkgJT4lIAogIGRpc3RpbmN0KCkKYGBgCgpgYGB7cn0KCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgc2VsZWN0KGZvb2QpICU+JSAKICBkaXN0aW5jdCgpCmBgYAoKTmljZSEKCiMjIyMgVW5kZXItY29uc3VtZWQgZm9vZHMKClRvIGNob29zZSB0aGUgY29sb3JzIGZvciBvdXIgcGxvdCB3ZSBjYW4gdXNlIHRoZSBgc2hvd19jb2woKWAgZnVuY3Rpb24gb2YgdGhlIGBzY2FsZXNgIHBhY2thZ2UgKHdoaWNoIGlzIGluc3RhbGxlZCB3aXRoIGBnZ3Bsb3QyYCBwYWNrYWdlKSB0byBwcmV2aWV3IGNvbG9yIG9wdGlvbnMgZnJvbSB0aGUgdmlyaWRpcyBwYWxldHRlIG9mIHRoZSBgdmlyaWRpc2AgcGFja2FnZS4KCmBgYHtyfQpzY2FsZXM6OiBzaG93X2NvbCh2aXJpZGlzX3BhbCgpKDMpKQpgYGAKCldlIHdpbGwgdXNlIHRoZSBgcG9zaXRpb25faml0dGVyZG9kZ2UoKWAgaW4gb3VyIGBwb3NpdGlvbmAgYXJndW1lbnQgb2YgYGdlb21fcG9pbnQoKWAgdG8gaW5kaWNhdGUgaG93IHRoZSBwb2ludHMgc2hvdWxkIGJlIGdyb3VwZWQgYnkgc2V4LgoKYGBge3IsIGZpZy53aWR0aCA9IDE3LCBmaWcuaGVpZ2h0PTE0fQojIGZpcnN0IGZpbHRlciB0aGUgdmFsdWVzClVuZGVyIDwtIGRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGRpcmVjdGlvbiA9PSAibG93IikgJT4lCiAgZmlsdGVyKFJlbGF0aXZlX1BlcmNlbnQgPCAxMTApICU+JQogIGdncGxvdChhZXMoeSA9IFJlbGF0aXZlX1BlcmNlbnQsIAogICAgICAgICAgICAgeCA9IGZvb2QsIAogICAgICAgICBjb2xvciA9IHNleCkpICsKIyBhZGRzIGdyZXkgcG9pbnRzIGZvciBlYWNoIGNvdW50cnkKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoKSwgCiAgICAgICAgICAgICAgICBjb2xvciA9ICJkYXJrIGdyZXkiLAogICAgICAgICAgICAgICAgYWxwaGEgPSA3LzEwLAogICAgICAgICAgICAgICAgIHNpemUgPSA3LAojIHRoaXMgc3BlY2lmaWVzIGhvdyB0byBzZXBhcmF0ZSB0aGUgcG9pbnRzCiAgICAgICAgICAgICBhZXMoZmlsbCA9IHNleCkpICsgCiMgYWRkIGJveHBsb3RzCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siICwKICAgICAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IDIuNSwKICAgICAgICAgICAgICAgICAgICBhZXMoZmlsbCA9IHNleCkpICsKIyB0aGlzIGFsbG93cyB1cyB0byB1c2Ugc3BlY2lmaWMgY29sb3JzCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSAKICAgICAgICAgICAgICAgICAgICAgICAgYygiIzQ4MTU2N0ZGIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIiMxRjk2OEJGRiIpKSArCiMgYWRkcyBsaW5lIGZvciBvcHRpbWFsIGFtb3VudAogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMDAsIAogICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAzKSArCiMgbWFudWFsbHkgY2hhbmdlcyB5IGF4aXMgYnJlYWtzCiAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9YygwLCAyNSwgNTAsIDc1LCAxMDApLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9YygwLCAyNSwgNTAsIDc1LCAKICAgICAgICAgICAgICAgICAgICAgICIxMDAlIFxuIG9wdGltYWwgYW1vdW50IikpCiMgY3JlYXRlcyBhIGxhcmdlciBibGFjayBwb2ludCBmb3IgdGhlIFVTIGRhdGEKVW5kZXIgPC0gVW5kZXIgKwogIGdlb21fcG9pbnQoZGF0YSA9IGRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgICAgIGZpbHRlcihkaXJlY3Rpb24gPT0gImxvdyIsCiAgICAgICAgIGxvY2F0aW9uX25hbWUgPT0gIlVuaXRlZCBTdGF0ZXMiKSwKICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZSgKICAgICBqaXR0ZXIud2lkdGggPSAwLjAxLAogICAgICBkb2RnZS53aWR0aCA9IDAuNyksIAogICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICBzaXplID0gMTEsCiAgICAgICAgIGFlcyhmaWxsID0gc2V4LCAKICAgICAgICAgICAgc2hhcGUgPSBsb2NhdGlvbl9uYW1lKSkKCiMgY3JlYXRlcyBhIHNtYWxsZXIgeWVsbG93IHBvaW50IG9uIHRvcCBmb3IgdGhlIFVTIGRhdGEKVW5kZXIgPC0gVW5kZXIgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogICAgICBmaWx0ZXIoZGlyZWN0aW9uID09ICJsb3ciLAogICAgICAgICBsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIiksCiAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoCiAgICBqaXR0ZXIud2lkdGggPSAwLjAxLAogICAgIGRvZGdlLndpZHRoID0gMC43KSwgCiAgICAgICAgICAgY29sb3IgPSAiI0ZGREYwMCIsCiAgICAgICAgICAgIHNpemUgPSA3LAogICAgICAgIGFlcyhmaWxsID0gc2V4LCAKICAgICAgICAgICBzaGFwZSA9IGxvY2F0aW9uX25hbWUpKSArCiMgbWFrZSB0aGUgcGxvdCBsb29rIG5pY2UKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA0MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDcwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMzIpLCAKICAgICAgICAjIHRoaXMgaXMgdXNlZnVsIGZvciByZW1vdmluZyB0aGUgbGVnZW5kCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDM1KSwgCiAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzUpLCAKICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkpICsKbGFicyh0aXRsZSA9ICJcbiBHbG9iYWwgY29uc3VtcHRpb24gb2YgZm9vZHMgYXNzb2NpYXRlZCB3aXRoXG5oZWFsdGggcmlzayB3aGVuIHVuZGVyLWNvbnN1bWVkIiwKICAgICAgICAgeCA9ICIiLCAKICAgICAgICAgeSA9ICJQZXJjZW50IGNvbnN1bXB0aW9uIHJlbGF0aXZlIFxuIHRvIGd1aWRlbGluZXMiKQoKVW5kZXIKYGBgCgojIyMjIE92ZXItY29uc3VtZWQgZm9vZHMKCldlIHdpbGwgdXNlIHRoZSBgZmFjZXRfem9vbSgpYCBmdW5jdGlvbiBvZiB0aGUgYGdnZm9yY2VgIHBhY2thZ2UgdG8gY3JlYXRlIGEgcGxvdCB3aXRoIGEgem9vbWVkIGluIHBvcnRpb24uCgpgYGB7ciwgZmlnLndpZHRoPTIwLCBmaWcuaGVpZ2h0PTE2fQpPdmVyIDwtIGRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGRpcmVjdGlvbiA9PSAiaGlnaCIpICU+JQogIGdncGxvdChhZXMoeSA9IFJlbGF0aXZlX1BlcmNlbnQsIAogICAgICAgICAgICAgeCA9IGZvb2QpKSArIAojIHRoaXMgYWRkcyBwb2ludHMgZm9yIGVhY2ggY291bnRyeQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZSgpLCAKICAgICAgICAgICAgICAgIGNvbG9yID0gImRhcmsgZ3JleSIsCiAgICAgICAgICAgICAgICBhbHBoYSA9IDcvMTAsCiMgdGhpcyBzcGVjaWZpZXMgaG93IHRvIHNlcGFyYXRlIHRoZSBwb2ludHMgZm9yIG1hbGUgYW5kIGZlbWFsZQogICAgICAgICAgICAgYWVzKGZpbGwgPSBzZXgpLAogICAgICAgICAgICAgICAgIHNpemUgPSA3KSAgKyAKIyB0aGlzIGFkZHMgYm94cGxvdHMKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCAKICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIgLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IDIuNSwKICAgICAgICAgICAgICAja2V5X2dseXBoID0gZHJhd19rZXlfcmVjdCksCiAgICAgICAgICAgICAgICBhZXMoZmlsbCA9IHNleCkpICsKIyB0aGlzIG1hbnVhbGx5IGNoYW5nZXMgYm94cGxvdCBjb2xvcnMKc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gCiAgICAgICAgICAgICAgICAgICAgICBjKCIjNDgxNTY3RkYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIiMxRjk2OEJGRiIpKSArCiMgdGhpcyBhZGRzIG9wdGltYWwgcmVkIGxpbmUKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwMCwgCiAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsKIyB0aGlzIGNoYW5nZXMgeSBheGlzIGJyZWFrcwpzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxMDAsIDUwMCwgMTAwMCwgMjAwMCksIAogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMTAwJSB0aHJlc2guIiwgNTAwLCAxMDAwLCAyMDAwKSkgKwojIHRoaXMgem9vbXMgaW4gdG8gcGFydCBvZiB0aGUgcGxvdAogZ2dmb3JjZTo6ZmFjZXRfem9vbSh5bGltID0gYygwLCAxMzAwKSkgKwojIHRoaXMgY2hhbmdlcyB0aGUgbGVnZW5kIGRpcmVjdGlvbgogIGd1aWRlcyhndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgICAgICAgICAgICAgIGxhYmVsLnZqdXN0ID0gLjUpKQoKIyBjcmVhdGVzIGEgbGFyZ2VyIGJsYWNrIHBvaW50IGZvciB0aGUgVVMgZGF0YQpPdmVyIDwtIE92ZXIgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogICAgZmlsdGVyKGRpcmVjdGlvbiA9PSAiaGlnaCIsCiAgICAgICBsb2NhdGlvbl9uYW1lID09ICJVbml0ZWQgU3RhdGVzIiksCiAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoCiAgICAgaml0dGVyLndpZHRoID0gMC4wMSwKICAgICAgZG9kZ2Uud2lkdGggPSAwLjcpLCAKICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICBzaXplID0gMTEsCiAgICAgICAgYWVzKGZpbGwgPSBzZXgsIAogICAgICAgICAgIHNoYXBlID0gbG9jYXRpb25fbmFtZSkpCgojIGNyZWF0ZXMgYSBzbWFsbGVyIHllbGxvdyBwb2ludCBvbiB0b3AgZm9yIHRoZSBVUyBkYXRhCk92ZXIgPC0gT3ZlciArIAogIGdlb21fcG9pbnQoZGF0YSA9IGRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKGRpcmVjdGlvbiA9PSAiaGlnaCIsCiAgICAgICAgICAgICAgICAgbG9jYXRpb25fbmFtZSA9PSAiVW5pdGVkIFN0YXRlcyIpLAogICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKAogICAgICAgICAgICAgICAgICBqaXR0ZXIud2lkdGggPSAwLjAxLAogICAgICAgICAgICAgICAgICBkb2RnZS53aWR0aCA9IDAuNyksCiAgICAgICAgICAgIGNvbG9yID0gIiNGRkRGMDAiLAogICAgICAgICAgICAgc2l6ZSA9IDcsCiAgICAgICAgIGFlcyhmaWxsID0gc2V4LCAKICAgICAgICAgICAgc2hhcGUgPSBsb2NhdGlvbl9uYW1lKSkgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKGJyZWFrcyA9ICJVbml0ZWQgU3RhdGVzIikgKwojIHRoaXMgbWFrZXMgdGhlIHBsb3QgbG9vayBuaWNlCiB0aGVtZV9saW5lZHJhdygpICsKIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDQwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMyKSwgCiAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICMgdGhpcyBpcyBmb3IgY2hhbmdpbmcgdGhlIHpvb20gdHJpYW5nbGUgY29sb3IKIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmV5ODYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTg2IiksCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSksIAogICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzUpLCAKICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gLjAxKSwKICAjIHRoaXMgaXMgZm9yIGNoYW5naW5nIHRoZSBsZWdlbmQgc3ltYm9sIHNpemUKbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDIsICJjbSIpLAogbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMiwgImNtIiksCiMgdGhpcyBpcyBmb3IgY2hhbmdpbmcgdGhlIGZpZ3VyZSBvdXRsaW5lCiBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLjUpKSArCmV4cGFuZF9saW1pdHMoeSA9IC0xMCkgKwpsYWJzKHRpdGxlID0gIiBHbG9iYWwgY29uc3VtcHRpb24gb2YgZm9vZHMgYXNzb2NpYXRlZCB3aXRoXG4gaGVhbHRoIHJpc2sgd2hlbiBvdmVyLWNvbnN1bWVkIiwKICAgICAgICAgeCA9ICIiLAogICAgICAgICB5ID0gIlBlcmNlbnQgY29uc3VtcHRpb24gcmVsYXRpdmUgXG4gdG8gZ3VpZGVsaW5lcyIpCgpPdmVyCmBgYAoKTGV0J3MgcHV0IHRoZSBwbG90cyB0b2dldGhlcjoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMjYsIGZpZy53aWR0aCA9IDE4fQpjb3dwbG90OjpwbG90X2dyaWQoT3ZlciwgVW5kZXIsIG5jb2wgPSAxKQoKYGBgCk5pY2UhCgoKIyMjIyBPdmVyLWNvbnN1bWVkIGJ5IEFnZSBHbG9iYWwgdHJlbmRzCgpOb3cgd2Ugd2lsbCBsb29rIGF0IEdsb2JhbCB0cmVuZHMgd2l0aCBhZ2UuIAoKVG8gbWFrZSB0aGlzIHBsb3Qgd2Ugd2lsbCB1c2UgdGhlIGBmYWNldF93cmFwX3BhZ2luYXRlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dmb3JjZWAgcGFja2FnZSB3aGljaCBhbGxvd3MgeW91IHRvIHNwZWNpZnkgdGhlIG51bWJlciBvZiBjb2x1bW5zIG9yIHJvd3MgZm9yIHRoZSBmYWNldHMuCgpgYGB7ciwgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSAxOH0KIApPdmVyX2FnZSA8LSBhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGRpcmVjdGlvbiA9PSAiaGlnaCIpICU+JQogIGZpbHRlcihSZWxhdGl2ZV9QZXJjZW50IDwgNDAwMCkgJT4lCiAgZ2dwbG90KGFlcyh5ID0gUmVsYXRpdmVfUGVyY2VudCwgCiAgICAgICAgICAgICB4ID0gYWdlX2dyb3VwX25hbWUsIAogICAgICAgICAgZmlsbCA9IGFnZV9ncm91cF9uYW1lKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIAogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiAsIAogICAgICAgICAgICAgICAgICAgIGFlcyhmaWxsID0gYWdlX2dyb3VwX25hbWUpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTAwLCAKICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIpICsKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjgpLCAKICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCksIAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwKSwgCiAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpLAogbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDEuMiwgImNtIiksCiAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMS4yLCAiY20iKSwKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSkgKwpsYWJzKHRpdGxlID0gIiBHbG9iYWwgY29uc3VtcHRpb24gYWNyb3NzIGFnZVxuICBvZiBmb29kcyBhc3NvY2lhdGVkXG4gd2l0aCBoZWFsdGggcmlzayB3aGVuIG92ZXItY29uc3VtZWQiLAogICAgICAgICB4ID0gIkFnZSIsIAogICAgICAgICB5ID0gIlxuUGVyY2VudCBjb25zdW1wdGlvbiByZWxhdGl2ZSBcbiB0byBndWlkZWxpbmVzIikrCmdnZm9yY2U6OmZhY2V0X3dyYXBfcGFnaW5hdGUofmZvb2QsIAogICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgCiAgICAgICAgICAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZSIpICsKc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSkKICAKT3Zlcl9hZ2UKYGBgCgoKSG1tbSB0aGVzZSBsb29rIGEgYml0IGZ1bm55IGJlY2F1c2UgdGhlIG91dGxpZXJzIGluIHRoZSBib3ggcGxvdHMgZm9yIHRoZSBmb29kcyBiZXNpZGVzIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMgYXJlIG1ha2luZyB0aGUgcmFuZ2UgbXVjaCBsYXJnZXIgdGhhbiB0aGUgYm94IHBsb3QgdGhlbXNlbHZlcy4gV2UgY2FuIGNhbGN1bGF0ZSB0aGUgdmFsdWVzIGZvciB0aGUgYm94IHBsb3RzIG91ciBzZWx2ZXMgdG8gZGVhbCB3aXRoIHRoaXM6CgpgYGB7cn0KY2FsY19zdGF0IDwtIGZ1bmN0aW9uKHgpIHsKICBjb2VmIDwtIDEuNQogIG4gPC0gc3VtKCFpcy5uYSh4KSkKICAjIGNhbGN1bGF0ZSBxdWFudGlsZXMKICBzdGF0cyA8LSBxdWFudGlsZSh4LCBwcm9icyA9IGMoMC4xLCAwLjI1LCAwLjUsIDAuNzUsIDAuOSkpCiAgbmFtZXMoc3RhdHMpIDwtIGMoInltaW4iLCAibG93ZXIiLCAibWlkZGxlIiwgInVwcGVyIiwgInltYXgiKQogIHJldHVybihzdGF0cykKfQpgYGAKClRoZW4gd2UgY2FuIHVzZSBpdCBpbiBvdXIgcGxvdCBjb2RlOgoKVGhpcyBpcyB0aGFua3MgdG8gdGhpczoKaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjUxMjQ4OTUvbm8tb3V0bGllcnMtaW4tZ2dwbG90LWJveHBsb3Qtd2l0aC1mYWNldC13cmFwCgpgYGB7ciwgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSAxOH0KI21hcF9kZihhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lIHNlbGVjdChSZWxhdGl2ZV9QZXJjZW50KSwgY2FsY19zdGF0KQoKT3Zlcl9hZ2UgPC0gYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihkaXJlY3Rpb24gPT0gImhpZ2giKSAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBSZWxhdGl2ZV9QZXJjZW50LCAKICAgICAgICAgICAgIHggPSBhZ2VfZ3JvdXBfbmFtZSwgCiAgICAgICAgICBmaWxsID0gYWdlX2dyb3VwX25hbWUpKSArCiAgIyBoZXJlIHdlIHdpbGwgcmVwbGFjZSBnZW9tX2JveHBsb3QoKSB5ZXQgc3RpbGwgY3JlYXRlIGJveHBsb3RzCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gY2FsY19zdGF0LCAKICAgICAgICAgICAgICAgICAgIGdlb20gPSAiYm94cGxvdCIsCiAgICAgICAgICBvdXRsaWVyLnNoYXBlID0gTkEsIAogICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIgLAogICAgICAgICAgICAgICAgICAgIGx3ZCA9IDEuMSwKICAgICAgICAgICAgICAgYWVzKGZpbGwgPSBhZ2VfZ3JvdXBfbmFtZSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMDAsIAogICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCAKICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICBzaXplID0gMikgKwogICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpLCAKICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUocGxvdC50aXRsZSA9ICBlbGVtZW50X3RleHQoc2l6ZSA9IDMwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI4KSwgCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCksIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLCAKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksCiAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgxLjIsICJjbSIpLAogICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMS4yLCAiY20iKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkpICsKbGFicyh0aXRsZSA9ICIgR2xvYmFsIGNvbnN1bXB0aW9uIGFjcm9zcyBhZ2VcbiAgb2YgZm9vZHMgYXNzb2NpYXRlZFxuIHdpdGggaGVhbHRoIHJpc2sgd2hlbiBvdmVyLWNvbnN1bWVkIiwKICAgICAgICAgeCA9ICJBZ2UiLCAKICAgICAgICAgeSA9ICJcblBlcmNlbnQgY29uc3VtcHRpb24gcmVsYXRpdmUgXG4gdG8gZ3VpZGVsaW5lcyIpICsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnlyb3cgPSBUUlVFKSkgKwogICAgZmFjZXRfd3JhcF9wYWdpbmF0ZSh+Zm9vZCwgbmNvbCA9IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpCiAgCk92ZXJfYWdlCmBgYAoKIyMjIyBVbmRlci1jb25zdW1lZCBieSBBZ2UgR2xvYmFsIFRyZW5kcwoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xOH0KVW5kZXJfYWdlIDwtIGFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBmaWx0ZXIoZGlyZWN0aW9uID09ICJsb3ciKSAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBSZWxhdGl2ZV9QZXJjZW50LCAKICAgICAgICAgICAgIHggPSBhZ2VfZ3JvdXBfbmFtZSwgCiAgICAgICAgICBmaWxsID0gYWdlX2dyb3VwX25hbWUpKSArCiAgIyBoZXJlIHdlIHdpbGwgcmVwbGFjZSBnZW9tX2JveHBsb3QoKQogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IGNhbGNfc3RhdCwgCiAgICAgICAgICAgICAgICAgICBnZW9tID0gImJveHBsb3QiLAogICAgICAgICAgb3V0bGllci5zaGFwZSA9IE5BLCAKICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgICAgIGx3ZCA9IDEuMSwKICAgICAgICAgICAgICAgYWVzKGZpbGwgPSBhZ2VfZ3JvdXBfbmFtZSkpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwMCwgCiAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAyKSArCiAgIHRoZW1lX2xpbmVkcmF3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSksIAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGZhY2V0X3dyYXBfcGFnaW5hdGUofmZvb2QsIG5yb3cgPSA1LCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyOCksIAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwgCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpICsKbGFicyh0aXRsZSA9ICJcbiBHbG9iYWwgY29uc3VtcHRpb24gYWNyb3NzIGFnZVxuICBvZiBmb29kcyBhc3NvY2lhdGVkXG4gd2l0aCBoZWFsdGggcmlzayB3aGVuIHVuZGVyLWNvbnN1bWVkIiwKICAgICAgICAgeCA9ICIiLCAKICAgICAgICAgeSA9ICJcblBlcmNlbnQgY29uc3VtcHRpb24gcmVsYXRpdmUgXG4gdG8gZ3VpZGVsaW5lcyIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKQogIApVbmRlcl9hZ2UKYGBgCgoKCgpOb3cgbGV0J3MgcHV0IGFsbCB0aGUgcGxvdHMgdG9nZXRoZXI6CgpgYGB7ciwgZmlnLmhlaWdodD0zMywgZmlnLndpZHRoID0gMzR9CmNvd3Bsb3Q6OnBsb3RfZ3JpZChPdmVyLCAKICAgICAgICAgICAgICAgICAgIE92ZXJfYWdlLCAKICAgICAgICAgICAgICAgICAgIFVuZGVyLCAKICAgICAgICAgICAgICAgICAgIFVuZGVyX2FnZSwgCiAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgCiAgICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygyLjUsIDEpKSAKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFfQpwbmcoZmlsZW5hbWUgPSBoZXJlOjpoZXJlKCJpbWciLCAibWFpbnBsb3QucG5nIiksCiAgICByZXMgPSAzMDAsIHdpZHRoID0gMzQsIGhlaWdodCA9IDMwLCB1bml0cyA9ICJpbiIpCmNvd3Bsb3Q6OnBsb3RfZ3JpZChPdmVyLCAKICAgICAgICAgICAgICAgICAgIE92ZXJfYWdlLCAKICAgICAgICAgICAgICAgICAgIFVuZGVyLCAKICAgICAgICAgICAgICAgICAgIFVuZGVyX2FnZSwgCiAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgCiAgICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygyLjUsIDEpKSArdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMSwgMSwgMSwgMSksICJjbSIpKQpkZXYub2ZmKCkKYGBgCgoKYGBge3IsIGV2YWwgPUZBTFNFLCBlY2hvID0gRkFMU0V9CgojIHdlIGFyZSB3b3JraW5nIHdpdGggdGhlIEdCRCBhYm91dCB0aGlzLi4uIGhvcGUgdG8gZml4IHRoaXMgaXNzdWUgYW5kIHRoZW4gd2Ugd2lsbCBub3QgbmVlZCB0byBpbmNsdWRlIGEgbm90ZSBhYm91dCB0aGlzOgojIEZvciBpbnN0cnVjdG9ycywgdGhlcmUgbWF5IGJlIHNvbWV0aGluZyB3cm9uZyB3aXRoIHRoZSBkYXRhIHJlZ2FyZGluZyB0cmFucyBmYXR0eSBhY2lkcyAtIGFzIHRoZSBkYXRhIGZvciBNYWxheXNpYSBpbiB0aGUgYWdlIHNlcGFyYXRlZCBkb2N1bWVudCBhcHBlYXJzIHRvIGJlIGRpZmZlcmVudCBmcm9tIHRoYXQgaW4gdGhlIGFnZSBjb2xsYXBzZWQgZGF0YToKCmFnZWNvbGxhcHNlZCA8LSBkaWV0X2FuZF9ndWlkZWxpbmVzICU+JSBmaWx0ZXIoZm9vZCA9PSAidHJhbnMgZmF0dHkgYWNpZHMiKSU+JSBzZWxlY3QobWVhbiwgbG9jYXRpb25fbmFtZSkKbm90YWdlY29sbGFwc2VkIDwtIGFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUgZmlsdGVyKGZvb2QgPT0gInRyYW5zIGZhdHR5IGFjaWRzIiklPiUgc2VsZWN0KG1lYW4sIGxvY2F0aW9uX25hbWUpCnJhbmdlKGFnZWNvbGxhcHNlZCRtZWFuKQpyYW5nZShub3RhZ2Vjb2xsYXBzZWQkbWVhbikKbm90YWdlY29sbGFwc2VkICU+JSBhcnJhbmdlKGRlc2MobWVhbikpCmFnZWNvbGxhcHNlZCAlPiUgYXJyYW5nZShkZXNjKG1lYW4pKQojaG1tbSB0aGUgbG93ZXN0IHZhbHVlIGZvciBtYWxheXNpYSBpcyAxMDYuLi4Kbm90YWdlY29sbGFwc2VkJT4lIGZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJNYWxheXNpYSIpICU+JSBhcnJhbmdlKGRlc2MoLW1lYW4pKQojIGJ1dCB0aGUgY29sbGFwc2VkIHZhbHVlIGlzIG11Y2ggbXVjaCBsb3dlci4uLgphZ2Vjb2xsYXBzZWQlPiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIk1hbGF5c2lhIikKCiMgdGhpcyBhbHNvIGxvb2tzIHByb2JsZW1hdGljOgojbm90IGFnZSBjb2xsYXBzZWQ6CnNlcF9hZ2VfZGlldF9kYXRhICU+JSBmaWx0ZXIoZm9vZCA9PSAic29kaXVtIiwgbG9jYXRpb25fbmFtZT09ICJNYWxheXNpYSIpICU+JXN1bW1hcmlzZShtaW4gPSBtaW4obWVhbikpCiNhZ2UgY29sbGFwc2VkOgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JWZpbHRlcihmb29kID09ICJzb2RpdW0iLCBsb2NhdGlvbl9uYW1lPT0gIk1hbGF5c2lhIikgJT4lc3VtbWFyaXNlKG1pbiA9IG1pbihtZWFuKSkKCgpzZXBfYWdlX2RpZXRfZGF0YSAlPiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIk1hbGF5c2lhIiwgZm9vZCA9PSAidHJhbnMgZmF0dHkgYWNpZHMiKSAlPiUgcHVsbChsb3dlcikKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIk1hbGF5c2lhIiwgZm9vZCA9PSAidHJhbnMgZmF0dHkgYWNpZHMiKSAlPiUgcHVsbChsb3dlcikKCiMjIyBjb25maXJtaW5nIHdpdGggcmF3IGRhdGE6CgpkaWV0X2RhdGEgPC0gcmVhZHI6OnJlYWRfY3N2KGhlcmUoImRvY3MiLCAKICAgICAgICAgICAgICAgICAgICAgICAiZGlldGFyeV9yaXNrX2V4cG9zdXJlX2FsbF9hZ2VzXzIwMTcuY3N2IikpCnNlcF9hZ2VfZGlldF9kYXRhIDwtIHJlYWRfY3N2KGhlcmUoImRvY3MiLCAKICAgICAgICAgICAgICAgICAgICAgICAiZGlldGFyeV9yaXNrX2V4cG9zdXJlX3NlcF9hZ2VzXzIwMTcuY3N2IikpCnNlcF9hZ2VfZGlldF9kYXRhICU+JSBmaWx0ZXIobG9jYXRpb25fbmFtZSA9PSAiTWFsYXlzaWEiLCByZWlfbmFtZSA9PSAiRGlldCBoaWdoIGluIHRyYW5zIGZhdHR5IGFjaWRzIikgJT4lIHB1bGwobG93ZXIpCmRpZXRfZGF0YSAlPiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIk1hbGF5c2lhIiwgcmVpX25hbWUgPT0gIkRpZXQgaGlnaCBpbiB0cmFucyBmYXR0eSBhY2lkcyIpICU+JSBwdWxsKGxvd2VyKQpzZXBfYWdlX2RpZXRfZGF0YSAlPiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIk1hbGF5c2lhIiwgcmVpX25hbWUgPT0gIkRpZXQgaGlnaCBpbiBzb2RpdW0iKSAlPiUgcHVsbChsb3dlcikKZGlldF9kYXRhICU+JSBmaWx0ZXIobG9jYXRpb25fbmFtZSA9PSAiTWFsYXlzaWEiLCByZWlfbmFtZSA9PSAiRGlldCBoaWdoIGluIHNvZGl1bSIpICU+JSBwdWxsKGxvd2VyKQpzZXBfYWdlX2RpZXRfZGF0YSAlPiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIk1hbGF5c2lhIiwgcmVpX25hbWUgPT0gIkRpZXQgbG93IGluIHBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcyIpICU+JSBwdWxsKGxvd2VyKQpkaWV0X2RhdGEgJT4lIGZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJNYWxheXNpYSIsIHJlaV9uYW1lID09ICJEaWV0IGxvdyBpbiBwb2x5dW5zYXR1cmF0ZWQgZmF0dHkgYWNpZHMiKSAlPiUgcHVsbChsb3dlcikKCgpzZXBfYWdlX2RpZXRfZGF0YSAlPiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIkNoaW5hIiwgcmVpX25hbWUgPT0gIkRpZXQgbG93IGluIHBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcyIpICU+JSBwdWxsKGxvd2VyKQpkaWV0X2RhdGEgJT4lIGZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJDaGluYSIsIHJlaV9uYW1lID09ICJEaWV0IGxvdyBpbiBwb2x5dW5zYXR1cmF0ZWQgZmF0dHkgYWNpZHMiKSAlPiUgcHVsbChsb3dlcikKCmBgYAoKCiMjICoqU3VtbWFyeSoqCioqKgoKIyMjIFN5bm9wc2lzCgpXZSBoYXZlIGV2YWx1YXRlZCBhdmVyYWdlIGNvbnN1bXB0aW9uIGVzdGltYXRlcyBvZiAxNSBkaWV0YXJ5IGZhY3RvcnMgd2l0aCBwcm9iYWJseSBub24tY29tbXVuaWNhYmxlIGRpc2Vhc2UgKE5DRCkgcmlzayBmcm9tIDE5NSBkaWZmZXJlbnQgY291bnRyaWVzIGFyb3VuZCB0aGUgd29ybGQuIFRvIGRvIHNvIHdlIGltcG9ydGVkIGRhdGEgZnJvbSBhIFBERiB1c2luZyB0aGUgYHBkZnRvb2xzYCBwYWNrYWdlLCBhcyB3ZWxsIGFzIGRhdGEgZnJvbSB0d28gQ1NWIGZpbGVzIHVzaW5nIGByZWFkcmAuIFdlIHVzZWQgYHRpZHl2ZXJzZWAgcGFja2FnZXMgc3VjaCBhcyBgZHBseXJgLCBgc3RyaW5ncmAsIGFuZCBgdGlkeWAgdG8gY2xlYW4gYW5kIGpvaW4gdGhlIGRhdGEgZnJvbSB0aGUgUERGIHdpdGggdGhlIENTViBmaWxlcy4gCgpXZSBsZWFybmVkIHRoYXQgcmVncmVzc2lvbiBpcyBhIHBvd2VyZnVsIGFuZCBmbGV4aWJsZSBzdGF0aXN0aWNhbCB0b29sIHRoYXQgc2ltcGxpZmllcyBvciBlc3RpbWF0ZXMgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMgdXNpbmcgYSBtYXRoZW1hdGljYWwgbW9kZWwuIFdlIGxlYXJuZWQgYWJvdXQgdGhlIHV0aWxpdHkgb2YgcmVncmVzc2lvbiB0ZWNobmlxdWVzIHRvIGNvbXBhcmUgZ3JvdXBzLCBsb29rIGZvciBhc3NvY2lhdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMsIGFuZCBwcmVkaWN0IG91dGNvbWVzIGJhc2VkIG9uIG11bHRpcGxlIHByZWRpY3RvciBvciBleHBsYW5hdG9yeSB2YXJpYWJsZXMuIFdlIHRoZW4gY29tcGFyZWQgdGhpcyB0byBvdGhlciBwb3B1bGFyIHRlc3RzIGxpa2UgdGhlICR0JC10ZXN0IGFuZCB0aGUgQU5PVkEuIFdlIGxlYXJuZWQgdGhhdCB0aGVzZSB0ZXN0cyBhcmUgYWN0dWFsbHkgZXF1aXZhbGVudCB0byBzcGVjaWFsaXplZCB0eXBlcyBvZiByZWdyZXNzaW9ucy4KCk91ciBzdGF0aXN0aWNhbCBhbmFseXNpcyBmb2N1c2VkIG9uIGV2YWx1YXRpbmcgZGlmZmVyZW5jZXMgaW4gdGhlIGNvbnN1bXB0aW9uIG9mIHJlZCBtZWF0IGFyb3VuZCB0aGUgd29ybGQgYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyBhbmQgYWNyb3NzIGRpZmZlcmVudCBhZ2UgZ3JvdXBzLiBGaXJzdCB3ZSBsb29rZWQgYXQgdGhlIGFzc3VtcHRpb25zIG9mIFskdCQtdGVzdHNdKGh0dHBzOi8vc3RhdHRyZWsuY29tL3N0YXRpc3RpY3MvZGljdGlvbmFyeS5hc3B4P2RlZmluaXRpb249dHdvLXNhbXBsZSUyMCR0JC10ZXN0KXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCByZWdyZXNzaW9ucywgYW5kIGRldGVybWluZWQgdGhhdCB0aGUgcmF0ZSBvZiByZWQgbWVhdCBjb25zdW1wdGlvbiByZWxhdGl2ZSB0byB0aGUgb3B0aW1hbCBndWlkZWxpbmUtc3VnZ2VzdGVkIGFtb3VudCB3YXMgcmlnaHQgc2tld2VkLiBXZSBsZWFybmVkIHRoYXQgd2UgY291bGQgdHJhbnNmb3JtIHRoZSBkYXRhIGJ5IHRha2luZyB0aGUgbG9nIG9mIHRoZXNlIHZhbHVlcyB0byBhY2hpZXZlIG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YS4gVG8gY29tcGFyZSBtYWxlcyBhbmQgZmVtYWxlcyB3ZSB1c2VkIGEgJHQkLXRlc3QgYW5kIGxlYXJuZWQgdGhhdCBhICR0JC10ZXN0IGlzIGEgc3BlY2lhbGl6ZWQgZm9ybSBvZiBhIGxpbmVhciByZWdyZXNzaW9uLiBUbyBjb21wYXJlIHRoZSAxNSBkaWZmZXJlbnQgYWdlIGdyb3VwcyB3ZSB1c2VkIGFuIEFOT1ZBIGFuZCBsZWFybmVkIHRoYXQgQU5PVkEgaXMgYWxzbyBhIHNwZWNpYWxpemVkIGZvcm0gb2YgbGluZWFyIHJlZ3Jlc3Npb24uIFdlIGV4YW1pbmVkIGhvdyB3ZSBvYnRhaW5lZCB0aGUgc2FtZSByZXN1bHRzIHVzaW5nIGVpdGhlciBzdGF0aXN0aWNhbCB0ZXN0LiBUaGlzIHdhcyBhbHNvIHRoZSBjYXNlIGlmIHdlIGxvb2tlZCBhdCB0aGUgZWZmZWN0IG9mIGdlbmRlciBhbmQgY29udHJvbGxlZCBmb3IgdGhlIHBhaXJlZCBjb3VudHJ5IHN0cnVjdHVyZSBpbiB0aGUgZGF0YSBieSBlaXRoZXIgaW5jbHVkaW5nIGBsb2NhdGlvbl9uYW1lYCBpbiB0aGUgbW9kZWwgYXMgYW5vdGhlciB0ZXJtIG9yIGJ5IHVzaW5nIGEgbWl4ZWQgZWZmZWN0cyBtb2RlbCB0byBjb250cm9sIGZvciB0aGlzIHN0cnVjdHVyZSBhcyBhIHJhbmRvbSBlZmZlY3QgYnV0IG5vdCBzcGVjaWZpY2FsbHkgdGVzdCBmb3IgdGhlIGluZmx1ZW5jZSBvZiBgbG9jYXRpb25fbmFtZWAgb24gcmVkIG1lYXQgY29uc3VtcHRpb24gZXN0aW1hdGVzLiBXZSBsZWFybmVkIHRoYXQgZml4ZWQgZWZmZWN0cyBhcmUgdGhvc2UgdGhhdCB3ZSB3aXNoIHRvIGV2YWx1YXRlLCB3aGlsZSByYW5kb20gZWZmZWN0cyBhcmUgdGhvc2UgdGhhdCBtYXkgaW5mbHVlbmNlIHRoZSByZWxhdGlvbnNoaXBzIG9mIG91ciB2YXJpYWJsZXMgb2YgaW50ZXJlc3QgYnV0IHRoYXQgd2UgZG8gbm90IHdpc2ggdG8gYWN0aXZlbHkgZXZhbHVhdGUuIFVzaW5nIHRoZXNlIHRlc3RzIGFuZCBtb2RlbHMsIHdlIGRldGVybWluZWQgdGhhdCBtYWxlcyBjb25zdW1lIG1vcmUgcmVkIG1lYXQgdGhhbiBmZW1hbGVzIG9uIGF2ZXJhZ2UgYXJvdW5kIHRoZSB3b3JsZC4gCgpPdXIgQU5PVkEgYW5hbHlzaXMgb2YgYWdlIGRldGVybWluZWQgdGhhdCBpbmRlZWQgdGhlcmUgaXMgYXQgbGVhc3Qgb25lIGFnZSBncm91cCB0aGF0IGNvbnN1bWVkIGEgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgYW1vdW50IG9mIHJlZCBtZWF0IGNvbXBhcmVkIHRvIHRoZSBvdGhlciBhZ2UgZ3JvdXBzLCBhbmQgdGhpcyB3YXMgc3RpbGwgdGhlIGNhc2Ugd2hlbiB3ZSBjb250cm9sbGVkIGZvciBgbG9jYXRpb25fbmFtZWAuIEhvd2V2ZXIsIHdlIGxlYXJuZWQgdGhhdCB0aGUgQU5PVkEgZG9lcyBub3QgcHJvdmlkZSBpbmZvcm1hdGlvbiBhYm91dCB3aGljaCBhZ2UgZ3JvdXBzIGFyZSBkaWZmZXJlbnQuIFdlIGxlYXJuZWQgaG93IHRoZSByZWdyZXNzaW9uIGNvdWxkIHByb3ZpZGUgc29tZSBxdWFudGlmaWNhdGlvbiBvZiB0aGUgZWZmZWN0IG9mIHNwZWNpZmljIGFnZSBncm91cHMgcmVsYXRpdmUgdG8gdGhlIHJlZmVyZW5jZSBhZ2UgZ3JvdXAuIEZ1cnRoZXJtb3JlLCBvdXIgZGF0YSB2aXN1YWxpemF0aW9ucyBhbGxvd2VkIHVzIHRvIGRldGVybWluZSB0aGF0IGluIGdlbmVyYWwgcmVkIG1lYXQgY29uc3VtcHRpb24gYXBwZWFycyB0byBiZSBoaWdoZXIgaW4gdGhlIHlvdW5nZXIgYWdlIGdyb3VwcyByZWxhdGl2ZSB0byB0aGUgb2xkZXIgYWdlIGdyb3Vwcy4gCgpGaW5hbGx5LCB3ZSBhbHNvIGxvb2tlZCBhdCBkaWZmZXJlbmNlcyBpbiByZWQgbWVhdCBjb25zdW1wdGlvbiBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgY291bnRyaWVzIGFuZCBzYXcgaW4gb3VyIEFOT1ZBIGFuYWx5c2lzIGFuZCBvdXIgcmVncmVzc2lvbiBhbmFseXNpcyB0aGF0IHRoZXJlIHdlcmUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMuIFdlIHdlcmUgYWJsZSB0byB1c2UgYSByZWdyZXNzaW9uIHRoYXQgaW5jbHVkZWQgYHNleGAsIGBhZ2VfZ3JvdXBfbmFtZWAsIGFuZCBgbG9jYXRpb25fbmFtZWAgdG8gZXZhbHVhdGUgdGhlIGluZmx1ZW5jZSBvZiBlYWNoIG9mIHRoZSB0aHJlZSBkZW1vZ3JhcGhpYyBmYWN0b3JzIG9uIGNvbnN1bXB0aW9uIHdoaWxlIGNvbnRyb2xsaW5nIG9yIGFjY291bnRpbmcgZm9yIHRoZSBvdGhlciB0d28uIE91ciByZXN1bHRzIGRlbW9uc3RyYXRlZCB0aGF0IGFsbCB0aHJlZSBpbmZsdWVuY2VkIG9yIHdlcmUgYXNzb2NpYXRlZCB3aXRoIHJlZCBtZWF0IGNvbnN1bXB0aW9uLgoKSW4gcHJlZm9ybWluZyBvdXIgc3RhdGlzdGljYWwgYW5hbHlzZXMgd2UgbGVhcm5lZCBhYm91dCB0aGUgYXNzdW1wdGlvbnMgb2YgdGhlICR0JC10ZXN0LCByZWdyZXNzaW9uLCBhbmQgdGhlIEFOT1ZBLiBXZSBhbHNvIGxlYXJuZWQgYWJvdXQgaW1wb3J0YW50IG1ldGhvZHMgdG8gdGVzdHMgdGhlc2UgYXNzdW1wdGlvbnMuCgpVc2luZyB0aGUgYGdncGxvdDJgIHBhY2thZ2Ugd2Ugd2VyZSBhYmxlIHRvIHZpc3VhbGl6ZSB0cmVuZHMgaW4gdGhlIGRhdGEgYW5kIHRvIGNvbXBhcmUgY29uc3VtcHRpb24gb2YgdGhlc2UgZGlldGFyeSBmYWN0b3JzIGluIHRoZSBVUyB3aXRoIHRoYXQgb2YgdGhlIG90aGVyIGNvdW50cmllcy4KCldlIHNlZSB0aGF0IHRoZSBwb3B1bGF0aW9ucyBpbiBtYW55IGNvdW50cmllcyBhcmUgb3Zlci1jb25zdW1pbmcgZm9vZHMgdGhhdCBhcmUgYXNzb2NpYXRlZCB3aXRoIGhlYWx0aCByaXNrIHdoZW4gb3Zlci1jb25zdW1lZC4gSW4gcGFydGljdWxhciBwcm9jZXNzZWQgbWVhdCBhbmQgc3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyBhcHBlYXIgdG8gYmUgdGhlIG1vc3Qgb3ZlciBjb25zdW1lZC4gSW1wb3J0YW50bHkgYm90aCBvZiB0aGVzZSBhcHBlYXIgdG8gYmUgY29uc3VtZWQgYXQgaGlnaGVyIHF1YW50aXRpZXMgYnkgbWFsZXMgYW5kIHlvdW5nZXIgYWR1bHRzLiBQZW9wbGUgaW4gdGhlIFVTICBhcHBlYXIgdG8gY29uc3VtZSBmZXdlciBzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2VzIHRoYW4gb3RoZXIgY291bnRyaWVzLCBob3dldmVyLCBwZW9wbGUgYXJlIHN0aWxsIG92ZXItY29uc3VtaW5nLiBQcm9jZXNzZWQgbWVhdCBob3dldmVyIGFwcGVhcnMgdG8gYmUgZXNwZWNpYWxseSBiYWQgaW4gdGhlIFVTLiBJbiB0ZXJtcyBvZiBmb29kIHRoYXQgbmVlZCB0byBiZSBjb25zdW1lZCBpbiBhZGVxdWF0ZSBhbW91bnRzIHRvIG92ZXJjb21lIGhlYWx0aCByaXNrLCBuZWFybHkgYWxsIGNvdW50cmllcyBmb3IgYWxsIGZhY3RvcnMgYXJlIG5vdCByZWFjaGluZyBndWlkZWxpbmUgbGV2ZWxzLiBIb3dldmVyLCB0aGVyZSBhcmUgc29tZSBjb3VudHJpZXMgY29uc3VtaW5nIG1vcmUgdGhhbiBhZGVxdWF0ZSBhbW91bnRzIG9mIGxlZ3VtZXMsIHZlZ2V0YWJsZXMsIGZydWl0cyBhbmQgZmliZXIuIFBlb3BsZSBpbiB0aGUgVVMgYXBwZWFyIHRvIGVhdCBtb3JlIG1pbGsgcHJvZHVjdHMgYW5kIGNvbnN1bWUgbW9yZSBvbWVnYS0zIGZhdHR5IGFjaWRzIGFuZCBjYWxjaXVtIHJpY2ggZm9vZHMgdGhhbiBvdGhlciBjb3VudHJpZXMuIEFsbCBjb3VudHJpZXMgaW5jbHVkaW5nIHRoZSBVUyBjb25zdW1lIHZlcnkgbG93IGxldmVscyBvZiBwb2x5dW5zYXR1cmF0ZWQgZmF0dHkgYWNpZHMuIFRoZXNlIFtwb2x5dW5zYXR1cmF0ZWQgZmF0dHkgYWNpZHNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BvbHl1bnNhdHVyYXRlZF9mYXQpIGFyZSBhYnVuZGFudCBpbiBzZWVkcywgbnV0cyBhbmQgYXZvY2Fkb3MsIGFzIHdlbGwgYXMgZmlzaC4gTGlrZWx5IHRoZSBsb3cgbGV2ZWwgb2YgY29uc3VtcHRpb24gb2YgbnV0cyBhbmQgc2VlZHMgY29udHJpYnV0ZXMgdG8gdGhlc2UgbG93IHBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkIGVzdGltYXRlcy4gVGhlIHN1cHBsZW1lbnRhcnkgdGFibGUgaW5jbHVkZWQgaW4gdGhlIGFydGljbGUgc3VnZ2VzdHMgdGhhdCBwb29yIGNvbnN1bXB0aW9uIG9mIHBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcyBpcyBhc3NvY2lhdGVkIHdpdGggaXNjaGVtaWMgaGVhcnQgZGlzZWFzZS4gVGhlIGFydGljbGUgdGFrZXMgdGhpcyBkYXRhIGZ1cnRoZXIgdG8gZXZhbHVhdGUgdGhlIGFzc29jaWF0aW9uIG9mIGNvbnN1bXB0aW9uIGxldmVscyBvZiB0aGVzZSBmb29kcyB3aXRoIG1vcnRhbGl0eS4KCkFuYWx5c2VzIGxpa2UgdGhlIG9uZSBpbiBvdXIgY2FzZSBzdHVkeSBhcmUgaW1wb3J0YW50IGZvciBkZWZpbmluZyB3aGljaCBncm91cHMgY291bGQgYmVuZWZpdCB0aGUgbW9zdCBmcm9tIGludGVydmVudGlvbnMsIGVkdWNhdGlvbiwgYW5kIHBvbGljeSBjaGFuZ2VzIHdoZW4gYXR0ZW1wdGluZyB0byBtaXRpZ2F0ZSBwdWJsaWMgaGVhbHRoIGNoYWxsZW5nZXMuIFlvdSBjYW4gc2VlIGluIHRoZSBbYXJ0aWNsZV0oaHR0cHM6Ly93d3cudGhlbGFuY2V0LmNvbS9hY3Rpb24vc2hvd1BkZj9waWk9UzAxNDAtNjczNiUyODE5JTI5MzAwNDEtOCl7dGFyZ2V0PSJfYmxhbmsifSBob3dldmVyIHRoYXQgbWFueSBhZGRpdGlvbmFsIGNvbnNpZGVyYXRpb25zIHdvdWxkIGJlIGludm9sdmVkIHRvIHBlcmZvcm0gYSBtb3JlIHRob3JvdWdoIGFuYWx5c2lzIHRvIGFkZXF1YXRlbHkgdW5kZXJzdGFuZCB0aGUgZGF0YSBlbm91Z2ggdG8gcmVjb21tZW5kIHBvbGljeSBjaGFuZ2VzLgoKCiMjICoqU3VnZ2VzdGVkIEhvbWV3b3JrKioKKioqCgpTdHVkZW50cyBjYW4gZXZhbHVhdGUgY29uc3VtcHRpb24gZXN0aW1hdGVzIG9mIGFub3RoZXIgZGlldGFyeSBmYWN0b3IgYmVzaWRlcyByZWQgbWVhdC4KCgojIyAqKkFkZGl0aW9uYWwgSW5mb3JtYXRpb24qKgoqKiogCgojIyMgSGVscGZ1bCBMaW5rcwoKPHU+VGVybXMgYW5kIGNvbmNlcHRzIGNvdmVyZWQ6PC91PiAgCgpbVGlkeXZlcnNlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltSU3R1ZGlvIGNoZWF0c2hlZXRzXShodHRwczovL3JzdHVkaW8uY29tL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8pe3RhcmdldD0iX2JsYW5rIn0gIApbSW50ZXJwdW5jdF0oaHR0cHM6Ly93d3cuc2hvcnR0dXRvcmlhbHMuY29tL21hYy1vcy1zcGVjaWFsLWNoYXJhY3RlcnMtc2hvcnRjdXRzL21pZGRsZS1kb3QuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgCltSZWd1bGFyIGV4cHJlc3Npb25zXShodHRwczovL3d3dy5yLWJsb2dnZXJzLmNvbS9yZWd1bGFyLWV4cHJlc3Npb25zLWV2ZXJ5LXItcHJvZ3JhbW1lci1zaG91bGQta25vdy8pe3RhcmdldD0iX2JsYW5rIn0gIApbSW5mZXJlbmNlXShodHRwczovL3d3dy5icml0YW5uaWNhLmNvbS9zY2llbmNlL2luZmVyZW5jZS1zdGF0aXN0aWNzKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1JlZ3Jlc3Npb25dKGh0dHBzOi8vbGluZGVsb2V2LmdpdGh1Yi5pby90ZXN0cy1hcy1saW5lYXIvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0RpZmZlcmVudCB0eXBlcyBvZiByZWdyZXNzaW9uXShodHRwczovL3d3dy5hbmFseXRpY3N2aWRoeWEuY29tL2Jsb2cvMjAxNS8wOC9jb21wcmVoZW5zaXZlLWd1aWRlLXJlZ3Jlc3Npb24vKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW09yZGluYXJ5IGxlYXN0IHNxdWFyZXMgbWV0aG9kXShodHRwOi8vc2V0b3NhLmlvL2V2L29yZGluYXJ5LWxlYXN0LXNxdWFyZXMtcmVncmVzc2lvbi8pe3RhcmdldD0iX2JsYW5rIn0gIApbUmVzaWR1YWxdKGh0dHBzOi8vd3d3LnN0YXRpc3RpY3Nob3d0by5kYXRhc2NpZW5jZWNlbnRyYWwuY29tL3Jlc2lkdWFsLyl7dGFyZ2V0PSJfYmxhbmsifSAgClskdCQtdGVzdHNdKGh0dHBzOi8vc3RhdHRyZWsuY29tL3N0YXRpc3RpY3MvZGljdGlvbmFyeS5hc3B4P2RlZmluaXRpb249dHdvLXNhbXBsZSUyMCR0JC10ZXN0KXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0FOT1ZBXShodHRwOi8vb25saW5lc3RhdGJvb2suY29tLzIvYW5hbHlzaXNfb2ZfdmFyaWFuY2UvaW50cm8uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgClskdCQtdGVzdHMgYW5kIEFOT1ZBIGFyZSBlcXVpdmFsZW50IHRvIHJlZ3Jlc3Npb25dKGh0dHBzOi8vc2NpZW50aWZpY2FsbHlzb3VuZC5vcmcvMjAxNy8wNi8wOC8kdCQtdGVzdC1hcy1saW5lYXItbW9kZWxzLXIvKXt0YXJnZXQ9Il9ibGFuayJ9IGFsc28gc2VlIFtoZXJlXShodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vZXZlcnl0aGluZy1pcy1qdXN0LWEtcmVncmVzc2lvbi01YTNiZjIyYzQ1OWMpe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtoZXJlXShodHRwczovL2xpbmRlbG9ldi5naXRodWIuaW8vdGVzdHMtYXMtbGluZWFyLyl7dGFyZ2V0PSJfYmxhbmsifSBhYm91dCBob3cgbWFueSBjb21tb25seSBrbm93biBzdGF0aXN0aWNhbCB0ZXN0cyBhcmUgc3BlY2lhbGl6ZWQgZm9ybXMgb2YgcmVncmVzc2lvbiAgCltOb3JtYWwgRGlzdHJpYnV0aW9uXShodHRwczovL3d3dy5waHlzaW9sb2d5Lm9yZy9kb2kvZnVsbC8xMC4xMTUyL2FkdmFuLjAwMDY0LjIwMTcpe3RhcmdldD0iX2JsYW5rIn0gIApbUS1RIHBsb3RdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9hZHZhbmNlZF9ncmFwaHMvcS1xX3Bsb3RzLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gIApbR3VpZGUgdG8gcmVzaWR1YWwgZGlhZ25vc3RpYyBwbG90c10oaHR0cHM6Ly9kYXRhLmxpYnJhcnkudmlyZ2luaWEuZWR1L2RpYWdub3N0aWMtcGxvdHMvKSBhbmQgW0V4YW1wbGVzXShodHRwOi8vZG9jcy5zdGF0d2luZy5jb20vaW50ZXJwcmV0aW5nLXJlc2lkdWFsLXBsb3RzLXRvLWltcHJvdmUteW91ci1yZWdyZXNzaW9uLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltSZXNpZHVhbCB2cyBmaXR0ZWQgcGxvdF0oaHR0cHM6Ly9vbmxpbmUuc3RhdC5wc3UuZWR1L3N0YXQ0NjIvbm9kZS8xMTgvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1NjYWxlLWxvY2F0aW9uIHBsb3RdKGh0dHBzOi8vYm9vc3RlZG1sLmNvbS8yMDE5LzAzL2xpbmVhci1yZWdyZXNzaW9uLXBsb3RzLXNjYWxlLWxvY2F0aW9uLXBsb3QuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgCltIb21vc2NlZGFzdGljaXR5IF0oaHR0cHM6Ly93d3cuc3RhdGlzdGljc3NvbHV0aW9ucy5jb20vaG9tb3NjZWRhc3RpY2l0eS8pe3RhcmdldD0iX2JsYW5rIn0gIApbSGV0ZXJvc2NlZGFzdGljaXR5XShodHRwczovL3N0YXRpc3RpY3NieWppbS5jb20vcmVncmVzc2lvbi9oZXRlcm9zY2VkYXN0aWNpdHktcmVncmVzc2lvbi8pe3RhcmdldD0iX2JsYW5rIn0gIApbSW50ZXJwcmV0aW5nIGBsbSgpYCBvdXRwdXRdKGh0dHBzOi8vZmVsaXBlcmVnby5naXRodWIuaW8vYmxvZy8yMDE1LzEwLzIzL0ludGVycHJldGluZy1Nb2RlbC1PdXRwdXQtSW4tUil7dGFyZ2V0PSJfYmxhbmsifSAgCltDb2VmZmljaWVudHNdKGh0dHBzOi8vd3d3LnRoZWFuYWx5c2lzZmFjdG9yLmNvbS9pbnRlcnByZXRpbmctcmVncmVzc2lvbi1jb2VmZmljaWVudHMvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0xpbmVhciBtaXhlZCBlZmZlY3RzIHJlZ3Jlc3Npb25dKGh0dHBzOi8vb3VyY29kaW5nY2x1Yi5naXRodWIuaW8vdHV0b3JpYWxzL21peGVkLW1vZGVscy8pe3RhcmdldD0iX2JsYW5rIn0gIApbU2F0dGVydGh3YWl0ZSBmb3JtdWxhXShodHRwczovL3d3dy5zdGF0aXN0aWNzaG93dG8uZGF0YXNjaWVuY2VjZW50cmFsLmNvbS9zYXR0ZXJ0aHdhaXRlLWZvcm11bGEvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW01vb2QncyBUd28tU2FtcGxlIFNjYWxlIFRlc3RdKGh0dHBzOi8vZmlsZXMuZXJpYy5lZC5nb3YvZnVsbHRleHQvRUQwNjU1NTkucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICAgCltTdGFuZGFyZCBkZXZpYXRpb25dKGh0dHBzOi8vd3d3LnN0YXRzZGlyZWN0LmNvbS9oZWxwL2Jhc2ljX2Rlc2NyaXB0aXZlX3N0YXRpc3RpY3Mvc3RhbmRhcmRfZGV2aWF0aW9uLmh0bSl7dGFyZ2V0PSJfYmxhbmsifSAgCltIb21vZ2VuZWl0eSBvZiBWYXJpYW5jZXMgYXNzdW1wdGlvbl0oaHR0cHM6Ly91Yy1yLmdpdGh1Yi5pby9hc3N1bXB0aW9uc19ob21vZ2VuZWl0eSl7dGFyZ2V0PSJfYmxhbmsifSAgIApbcG9seXVuc2F0dXJhdGVkIGZhdHR5IGFjaWRzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Qb2x5dW5zYXR1cmF0ZWRfZmF0KXt0YXJnZXQ9Il9ibGFuayJ9IAoKCjx1PlRlc3RzIG9mIEhvbW9nZW5laXR5IG9mIFZhcmlhbmNlIGZvciAzIG9yIG1vcmUgZ3JvdXBzOjwvdT4KCltCYXJ0bGV0dCdzIHRlc3RdKGh0dHBzOi8vd3d3Lml0bC5uaXN0Lmdvdi9kaXY4OTgvaGFuZGJvb2svZWRhL3NlY3Rpb24zL2VkYTM1Ny5odG0pe3RhcmdldD0iX2JsYW5rIn0gIApbRmxpZ25lci1LaWxsZWVuXShodHRwOi8vd2lraS5zdGF0LnVjbGEuZWR1L3NvY3IvaW5kZXgucGhwL0FQX1N0YXRpc3RpY3NfQ3VycmljdWx1bV8yMDA3X05vblBhcmFtX1ZhckluZGVwKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0xldmVuZSdzIHRlc3RdKGh0dHBzOi8vd3d3Lml0bC5uaXN0Lmdvdi9kaXY4OTgvaGFuZGJvb2svZWRhL3NlY3Rpb24zL2VkYTM1YS5odG0pe3RhcmdldD0iX2JsYW5rIn0gIAogCgo8dT5PdGhlciBoZWxwZnVsIGxpbmtzOjwvdT4KCltMb25nIGFuZCBXaWRlIERhdGEgRm9ybWF0c10oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1oZWFsdGhleHBlbmRpdHVyZS9vY3MtaGVhbHRoZXhwZW5kaXR1cmUuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICAKW0Rpc3RyaWJ1dGlvbnNdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9pbnRyb2R1Y3Rpb24vZGlzdHJpYnV0aW9ucy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IApbU2tld2VkIERpc3RyaWJ1dGlvbnNdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9nbG9zc2FyeS9za2V3Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gCltCaW1vZGFsIERpc3RyaWJ1dGlvbl0oaHR0cDovL29ubGluZXN0YXRib29rLmNvbS8yL2ludHJvZHVjdGlvbi9kaXN0cmlidXRpb25zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gCltnZ3Bsb3QyXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWhlYWx0aGV4cGVuZGl0dXJlL29jcy1oZWFsdGhleHBlbmRpdHVyZS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIApbU2hhcGlyby1XaWxrIFRlc3RdKGh0dHA6Ly93d3cuc3RhdGlzdGljczR1LmluZm8vZnVuZHN0YXRfZW5nL2VlX3NoYXBpcm9fd2lsa190ZXN0Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAKW1BhaXJlZCBEYXRhXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM1NTc5NDY1Lyl7dGFyZ2V0PSJfYmxhbmsifSAgCltXZWxjaCdzICR0JC10ZXN0XShodHRwczovL3d3dy5zdGF0aXN0aWNzaG93dG8uZGF0YXNjaWVuY2VjZW50cmFsLmNvbS93ZWxjaHMtdGVzdC1mb3ItdW5lcXVhbC12YXJpYW5jZXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIApbUGFyYW1ldHJpYyBhbmQgTm9ucGFyYW1ldHJpYyBNZXRob2RzXShodHRwczovL3d3dy5tYXlvLmVkdS9yZXNlYXJjaC9kb2N1bWVudHMvcGFyYW1ldHJpYy1hbmQtbm9ucGFyYW1ldHJpYy1kZW15c3RpZnlpbmctdGhlLXRlcm1zL2RvYy0yMDQwODk2MCl7dGFyZ2V0PSJfYmxhbmsifSAgIApbVmFyaWFuY2VdKGh0dHBzOi8vc3RhdHRyZWsuY29tL3N0YXRpc3RpY3MvZGljdGlvbmFyeS5hc3B4P2RlZmluaXRpb249dmFyaWFuY2Upe3RhcmdldD0iX2JsYW5rIn0gIApbQmFsYW5jZWQgU3R1ZHkgRGVzaWduXShodHRwczovL3d3dy5zdGF0aXN0aWNzaG93dG8uZGF0YXNjaWVuY2VjZW50cmFsLmNvbS9iYWxhbmNlZC1hbmQtdW5iYWxhbmNlZC1kZXNpZ25zLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltJbmRlcGVuZGVudCBPYnNlcnZhdGlvbnNdKGh0dHBzOi8vd3d3LnN0YXQuY211LmVkdS9+Y3NoYWxpemkvMzYtMjIwL2xlY3R1cmUtNS5wZGYpe3RhcmdldD0iX2JsYW5rIn0gIApbVHJhbnNmb3JtYXRpb25dKGh0dHBzOi8vd3d3LnN0YXRpc3RpY3Nob3d0by5kYXRhc2NpZW5jZWNlbnRyYWwuY29tL3RyYW5zZm9ybWF0aW9uLXN0YXRpc3RpY3MvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1Blcm11dGF0aW9uL1Jlc2FtcGxpbmcgTWV0aG9kc10oaHR0cHM6Ly9qaHUtYWR2ZGF0YXNjaS5naXRodWIuaW8vMjAxOS9sZWN0dXJlcy8yMS1yZXNhbXBsaW5nLXRlY2huaXF1ZXMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgIApbQ2VudHJhbCBMaW1pdCBUaGVvcmVtXShodHRwczovL3d3dy5hbmFseXRpY3N2aWRoeWEuY29tL2Jsb2cvMjAxOS8wNS9zdGF0aXN0aWNzLTEwMS1pbnRyb2R1Y3Rpb24tY2VudHJhbC1saW1pdC10aGVvcmVtLyl7dGFyZ2V0PSJfYmxhbmsifSAKW1dpbGNveG9uIFNpZ25lZCBSYW5rIFRlc3RdKGh0dHA6Ly93d3cuYmlvc3RhdGhhbmRib29rLmNvbS93aWxjb3hvbnNpZ25lZHJhbmsuaHRtbCkgICAKW1dpbGNveG9uIFJhbmsgU3VtIFRlc3RdKGh0dHA6Ly9zcGh3ZWIuYnVtYy5idS5lZHUvb3RsdC9tcGgtbW9kdWxlcy9icy9iczcwNF9ub25wYXJhbWV0cmljL0JTNzA0X05vbnBhcmFtZXRyaWM0Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gIApbVHdvLXNhbXBsZSBLb2xtb2dvcm92LVNtaXJub3YgVGVzdF0oaHR0cHM6Ly93d3cuaXRsLm5pc3QuZ292L2Rpdjg5OC9zb2Z0d2FyZS9kYXRhcGxvdC9yZWZtYW4xL2F1eGlsbGFyL2tzMnNhbXAuaHRtKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1R5cGUgMSBFcnJvcl0oaHR0cHM6Ly93ZWIubWEudXRleGFzLmVkdS91c2Vycy9ta3Mvc3RhdG1pc3Rha2VzL2Vycm9ydHlwZXMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgCltwLXZhbHVlXShodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vcC12YWx1ZXMtZXhwbGFpbmVkLWJ5LWRhdGEtc2NpZW50aXN0LWY0MGE3NDZjZmM4KXt0YXJnZXQ9Il9ibGFuayJ9ICAKW011bHRpcGxlIFRlc3RpbmddKGh0dHBzOi8vd3d3LmdzLndhc2hpbmd0b24uZWR1L2FjYWRlbWljcy9jb3Vyc2VzL2FrZXkvNTYwMDgvbGVjdHVyZS9sZWN0dXJlMTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIApbQm9uZmVycm9uaSBNZXRob2Qgb2YgTXVsdGlwbGUgVGVzdGluZyBDb3JyZWN0aW9uXShodHRwOi8vbWF0aHdvcmxkLndvbGZyYW0uY29tL0JvbmZlcnJvbmlDb3JyZWN0aW9uLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0KCjx1PlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OiA8L3U+CgogUGFja2FnZSAgIHwgVXNlIGluIHRoaXMgY2FzZSBzdHVkeSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCltoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhICAKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIENTViBmaWxlIGRhdGEgIApbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGFycmFuZ2UvZmlsdGVyL3NlbGVjdC9jb21wYXJlIHNwZWNpZmljIHN1YnNldHMgb2YgdGhlIGRhdGEgIApbc2tpbXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9za2ltci9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBnZXQgYW4gb3ZlcnZpZXcgb2YgZGF0YSAgICAKW3BkZnRvb2xzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcGRmdG9vbHMvcGRmdG9vbHMucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byByZWFkIGEgUERGIGludG8gUiAgIApbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvc3RyaW5nci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFuaXB1bGF0ZSB0aGUgdGV4dCB3aXRoaW4gdGhlIFBERiBvZiB0aGUgZGF0YSAgIApbbWFncml0dHJdKGh0dHBzOi8vbWFncml0dHIudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byB1c2UgdGhlIGAlPD4lYCBwaXBpbmcgb3BlcmF0b3IgIApbcHVycnJdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHBlcmZvcm0gZnVuY3Rpb25zIG9uIGFsbCBjb2x1bW5zIG9mIGEgdGliYmxlICAgClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICB8IHRvIGNyZWF0ZSBkYXRhIG9iamVjdHMgdGhhdCB3ZSBjYW4gbWFuaXB1bGF0ZSB3aXRoICBkcGx5ci9zdHJpbmdyL3RpZHlyL3B1cnJyICAKW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBzZXBhcmF0ZSBkYXRhIHdpdGhpbiBhIGNvbHVtbiBpbnRvIG11bHRpcGxlIGNvbHVtbnMgCltnZ3Bsb3QyXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYWtlIHZpc3VhbGl6YXRpb25zIHdpdGggbXVsdGlwbGUgbGF5ZXJzICAKW2dncHVicl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dncHVici9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gZWFzaWx5IGFkZCByZWdyZXNzaW9uIGxpbmUgZXF1YXRpb25zIHRvIHBsb3RzICAKW2ZvcmNhdHNdKGh0dHBzOi8vZm9yY2F0cy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIGNoYW5nZSBkZXRhaWxzIGFib3V0IGZhY3RvcnMgKGNhdGVnb3JpY2FsIHZhcmlhYmxlcykgIApbbG1lclRlc3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9sbWVyVGVzdC9sbWVyVGVzdC5wZGYpfCB0byBwZXJmb3JtIGxpbmVhciBtaXhlZCBtb2RlbCB0ZXN0aW5nICAgCltjYXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jYXIvY2FyLnBkZil8IHRvIHBlcmZvcm0gTGV2ZW5lJ3MgVGVzdCBvZiBIb21vZ2VuZWl0eSBvZiBWYXJpYW5jZXMgICAKW2dnaXJhcGhdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ2lyYXBoL2luZGV4Lmh0bWwpfCB0byBtYWtlIHBsb3RzIGludGVyYWN0aXZlICAgCltnZ2ZvcmNlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dmb3JjZS9nZ2ZvcmNlLnBkZil8IHRvIG1vZGlmeSBmYWNldHMgaW4gcGxvdHMgIApbdmlyaWRpc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3ZpcmlkaXMvdmlnbmV0dGVzL2ludHJvLXRvLXZpcmlkaXMuaHRtbCl8IHRvIHBsb3QgaW4gY29sb3IgcGFsZXR0ZSAgICAKW2Nvd3Bsb3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jb3dwbG90L3ZpZ25ldHRlcy9pbnRyb2R1Y3Rpb24uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGFsbG93IHBsb3RzIHRvIGJlIGNvbWJpbmVkICAgCgojIyMgU2Vzc2lvbiBJbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCiMjIyBBY2tub3dsZWRnZW1lbnRzCgpXZSB3b3VsZCBsaWtlIHRvIGFja25vd2xlZGdlIFtKZXNzaWNhCkZhbnpvXShodHRwczovL2Jpb2V0aGljcy5qaHUuZWR1L3Blb3BsZS9wcm9maWxlL2plc3NpY2EtZmFuem8vKSBmb3IKYXNzaXN0aW5nIGluIGZyYW1pbmcgdGhlIG1ham9yIGRpcmVjdGlvbiBvZiB0aGUgY2FzZSBzdHVkeS4KCldlIHdvdWxkIGFsc28gbGlrZSB0byBhY2tub3dsZWRnZSB0aGUgW0Jsb29tYmVyZyBBbWVyaWNhbiBIZWFsdGgKSW5pdGlhdGl2ZV0oaHR0cHM6Ly9hbWVyaWNhbmhlYWx0aC5qaHUuZWR1LykgZm9yIGZ1bmRpbmcgdGhpcyB3b3JrLgoKCg==